Skip to content Skip to sidebar Skip to footer

Calling Arbitrary Function With Javascript 'apply'

I want to pass a varying number of argument to varying functions. I set up this basic test: function overview(arg1, arg2, arg3) { console.info('arg1 is ' + arg1); console.i

Solution 1:

this does not make sense in your context.

You have to define the functions in the global scope, or on another namespace, and use window, or the name of that namespace instead of this.

// Globally:    functionmodules(method, args) {
    window[method].apply(null, args);
}
modules('overview', ['test1', 'test2']);​

// Locally:var namespace = {};
namespace.overview = overview; // Defined previouslyfunctionmodules(method, args) {
    namespace[method].apply(null, args);
}
modules('overview', ['test1', 'test2']);​

If you want to use this method locally, without predefining a namespace, there is no other option than using eval:

// Locallyfunctionmodules(method, args) {
    eval(method).apply(null, args);
}
modules('overview', ['test1', 'test2']);​

Expanding the implementation:

If you want to handle unknown functions without throwing errors, use:

functionmodules(method, args) {
    var ns = window; // or namespace (method 2)    or eval(method)  (method 3)if (ns.hasOwnProperty(method) && typeof ns.method === 'function') {
        ns.apply(null, args);
    } else {
        console.log(' Unknown method: ' + method);
    }
}

Demos

  1. Global: http://jsfiddle.net/QFpRc/4/
  2. Local + namespace: http://jsfiddle.net/QFpRc/3/
  3. Local + eval: http://jsfiddle.net/QFpRc/2/

Solution 2:

Your reference to this in the modules function declaration points to the modules objects. Since modules doesn't have an 'overview' property, there is no 'overview' method to invoke. As @Rob W stated, you could explicitly reference the global window object, where your functions are defined, or you could define your own object:

var myObj = {
    overview: function(arg1, arg2, arg3) {
        console.info('arg1 is ' + arg1);
        console.info('arg2 is ' + arg2);
        console.info('arg3 is ' + arg3);
    },

    modules: function(method, args) {
        this[method].apply(null, args);
    }
};

myObj.modules('overview', newArray('test1', 'test2'));

See http://jsfiddle.net/QFpRc/1/ for a live example.

Solution 3:

Your code will perform faster if you used Function.prototype.bind instead of passing parameters thru a proxy function. Bind will save processing time and memory by applying the context and routing arguments before the actual function call

functionoverview(arg1,arg2,arg3){
  console.info('arg1 is ' + arg1);
  console.info('arg2 is ' + arg2);
  console.info('arg3 is ' + (arg3 || this.foo));
}
var context = { foo:'bar' };
var contextOverview = overview.bind(context);
var modOverview = function(){}.apply.bind(overview.bind(context), context);

modOerview(['test1','test1'])

A closure'd variant might look something like:

var importModule = (function(){
  var mods = {
    overview:function(arg1,arg2,arg3){
      console.info('arg1 is ' + arg1);
      console.info('arg2 is ' + arg2);
      console.info('arg3 is ' + (arg3 || this.foo()));
      console.warn('This context is ' + this);
    }
  };
  returnfunctionexportMod(name, context){
    var mod = mods[name].bind(context);
    return mod.apply.bind(mod,null);
  }
})();

var myContext = (function(){
  var foo = 'bar';
  var overview;
  var context = {
    overview:function(){ returnoverview() },
    foo:function(){ return foo },
    toString:function(){ return'my context!' }
  };
  overview = importModule('overview', context);
  return context;
})();

myContext.overview(['test1','test2']);

That being said, why don't you just call the function like normal? I mean, if you know the context and the function name.... .. .

Post a Comment for "Calling Arbitrary Function With Javascript 'apply'"