subeeshb
subeeshb

Reputation: 476

Javascript variable scope when dynamically referencing functions

I'm trying to create a function that creates a "proxy" around an object's method. This "proxy" will be used to handle web requests and then call the target method. The proxy function looks similar to this:

var proxy = function(c) {
  var proxy = {};
  for(var member in c) {
    var args = c[member].toString().match (/function\s*\w*\s*\((.*?)\)/)[1].split (/\s*,\s*/);
    proxy[member] = function(params) {
      var methodArgs = args.map(function(argName) {
        return params[argName];
      });
      return c[member].apply(c, methodArgs);
    }
  }
  return proxy;
};

So if I have this original controller,

var c = {
  sum: function(x, y) {
    return x + y;
  },

  multiply: function(x, y) {
    return x * y;
  }
};

calling proxy(c) on this will return a proxy object with sum() and multiply() functions. However, because of the scope of the member variable in the proxy() function, it will always call the last referenced function in c - in this case, multiply().

var cProxy = proxy(c);

//this should call c.sum, but instead calls c.multiply
cProxy.sum({
  x: 3,
  y: 8
});

How would I reference the right function in the proxy() function so that the right method gets called?

Upvotes: 0

Views: 53

Answers (2)

james emanon
james emanon

Reputation: 11807

The following worked for me, just create a closure for member

var proxy = function(c) {
  var proxy = {};
  for(var member in c) {
    !function(member){
        var args = c[member].toString().match (/function\s*\w*\s*\((.*?)\)/)[1].split (/\s*,\s*/);
        proxy[member] = function(params) {
          var methodArgs = args.map(function(argName) {
            return params[argName];
          });
          return c[member].apply(c, methodArgs);
        }
    }(member)
  }
  return proxy;
};



console.log( cProxy.sum({x: 3,y: 8})) // returns 11
console.log( cProxy.multiply({x: 3,y: 8})) //returns 24

Upvotes: 1

Rudie
Rudie

Reputation: 53781

One way is to wrap the inside of the loop in a function to create another scope. It looks weird though:

    proxy[member] = (function(member) {
        return function(params) {
            var methodArgs = args.map(function(argName) {
                return params[argName];
            });
            return c[member].apply(c, methodArgs);
        };
    })(member);

Demo: http://jsfiddle.net/rudiedirkx/t5ovkrw9/

Another way is to use let member in c, which creates a slightly smaller scope than var, but let isn't in most browsers yet.

Yet another way is to use .bind to stick arguments or context to a function. That doesn't really work, because you're already using context and arguments.

Upvotes: 1

Related Questions