8

I'm having a difficulty calling a function inside of another function when its name is in a variable:

var obj = {}

obj.f = function() {
  var inner = {
    a: function() {
      function b() {
        alert('got it!');
      }
      b(); // WORKS AS EXPECTED
      x = 'b';
      [x](); // DOESN'T WORK, NEITHER this[x]() window[x](), etc.
    }
  }
  inner.a();
}

obj.f();

I tried prefixing [x]() with different scope paths but so far w/o success. Searching existing answers did not turn up anything. It works with this[x]() if b() is placed directly inside object inner. I would like to keep b() as a function inside function a() because of variable scope in function a(), otherwise I would need to pass many parameters to b().

//// Re duplicate question: Quentin provided a more elegant answer in this thread imo.

Gonki
  • 567
  • 1
  • 8
  • 17

6 Answers6

19

There is no sensible way of accessing an arbitrary variable using a string matching the name of the variable. (For a very poor way to do so, see eval).

[x](); // DOESN'T WORK

You're trying to call an array as a function

NEITHER this[x]()

The function isn't a property of the inner object.

window[x](), etc.

Since it isn't a global, it isn't a property of the window object either.


If you need to call a function based on the value of a string variable, then organise your functions in an object and access them from that.

  function b() {
    alert('got it!');
  }
  var myFunctions = {
      b: b
  };
  x = 'b';
  myFunctions[x](); 
Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
3

Try this. Currently you are assigning string to variable x, instead of a function variable.

 x = b;
 x();
msapkal
  • 8,268
  • 2
  • 31
  • 48
  • perhaps it could have worked if value b were assigned directly. it comes from a calculation. it's not real code in the example. – Gonki Jan 13 '14 at 11:12
3

The problem is with your assignment

use x = b instead of x = 'b' to assign the function object as the latter just assigns the string into x.

Once you fix your assignment you can invoke the function as

x();
a.x();
a[x]();

etc.

2

You should make array for the function and then access using name in your variable as follow:

var obj = {}

obj.f = function() {
  var inner = {
    a: function() {
      // set up the possible functions:
      var myFuncs = {
              b: function b() {alert('got it!');}
              };
      //b(); // WORKS AS EXPECTED --> commented this code
      x = 'b';
      myFuncs[x]();    
    }
  }
  inner.a();
}
Bhavesh Kachhadiya
  • 3,902
  • 3
  • 15
  • 20
1

The function declaration b will be captured in the closure of the anonymous function expression assigned as a.

  1. When var is used in a closure, there is no (available in JavaScript) Object which gets assigned a property similar to what happens with window in the Global Scope.
  2. Writing a function declaration effectively vars the name of the function.

If you really want to access a variable (i.e. b) by String, you will either need to create an Object which holds b similar to what you've done for a, or (and possibly dangerously) rely on an eval to convert "b" to b.

If you can't create the whole Object ahead-of-time, you can use this format

/* in (higher?) scope */
var fnRef = {};
// now when you
function b() {/* define as desired */}
// also keep a ref.
fnRef['b'] = b;
// fnRef['b']() will work **after this line**
Paul S.
  • 64,864
  • 9
  • 122
  • 138
1

let's say your code is like this:

//instead of x = 'b'
x = function(){}

then your solution could be like this:

var obj = {}

obj.f = function() {
  var inner = {
    a: function() {
      function b() {
        alert('got it!');
      }
      b(); // WORKS AS EXPECTED
      //you can define it as a variable
      var x = function(){};
      //and call it like this
      x();

      //or define it like this
      this[x] = function(){};
      //and call it like this
      this[x]();

      //but you are creating an array [x] which is not a function
      //and you are trying to call an array????
      [x](); // DOESN'T WORK, NEITHER this[x]() window[x](), etc.
    }
  }
  inner.a();
}

obj.f();
Mehran Hatami
  • 12,723
  • 6
  • 28
  • 35