使用Javascript'apply'调用任意函数

时间:2012-02-23 14:21:07

标签: javascript

我想将不同数量的参数传递给不同的函数。我设置了这个基本测试:

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

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

modules('overview', new Array('test1', 'test2'));​

所以,我使用'apply'将带有参数的数组通过'modules'函数传递给'overview'函数。对于this[method]部分,这种方式正常,除了。我在这个Q& A:Calling dynamic function with dynamic parameters in Javascript中读到了这一点,看起来很奇妙。但是,我一直收到'TypeError'错误,我无法弄清楚如何解决这个问题。

当然,我可以在模块函数中使用switch来调用正确的方法,但这是不必要的批量(希望如此!)。我已经制作了一个JSFiddle来“摆弄”:http://jsfiddle.net/QFpRc/。希望任何人都可以解决和/或解释这一点。

3 个答案:

答案 0 :(得分:1)

this在您的上下文中没有意义。

您必须在全局范围或其他命名空间中定义函数,并使用window或该命名空间的名称而不是this

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

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

如果要在本地使用此方法,而不预先定义命名空间,除了使用eval之外别无选择:

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

扩展实施:

如果您想在不抛出错误的情况下处理未知函数,请使用:

function modules(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);
    }
}

演示

  1. 全球:http://jsfiddle.net/QFpRc/4/
  2. Local + namespace:http://jsfiddle.net/QFpRc/3/
  3. 本地+评估:http://jsfiddle.net/QFpRc/2/

答案 1 :(得分:1)

this函数声明中对modules的引用指向modules个对象。由于modules没有'overview'属性,因此没有'overview'方法可以调用。正如@Rob W所述,您可以显式引用定义函数的全局window对象,或者您可以定义自己的对象:

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', new Array('test1', 'test2'));

有关实例,请参阅http://jsfiddle.net/QFpRc/1/

答案 2 :(得分:0)

如果您使用Function.prototype.bind而不是通过代理函数传递参数,您的代码将执行得更快。绑定将通过在实际函数调用之前应用上下文和路由参数来节省处理时间和内存

function overview(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'])

closure'd变体可能类似于:

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);
    }
  };
  return function exportMod(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(){ return overview() },
    foo:function(){ return foo },
    toString:function(){ return 'my context!' }
  };
  overview = importModule('overview', context);
  return context;
})();

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

话虽如此,你为什么不像正常一样调用这个函数?我的意思是,如果你知道上下文和函数名...... ....