如何动态创建命名函数而忽略范围?

时间:2014-11-18 17:32:37

标签: javascript

这有效:

var i = 'foo';
eval('function '+i+'(param) { this.param = param; return this; }');
console.log(foo); // [Function: foo]

这不是:

['bar', 'quux'].forEach(function(i) {
    eval('function '+i+'(param) { this.param = param; return this; }');
});
console.log(bar); // ReferenceError: bar is not defined

显然,forEach函数或其从属范围会混淆事物。我检查过bar函数是否可用,但它不能在外面存活。

5 个答案:

答案 0 :(得分:3)

forEach回调会创建一个闭包。封闭中定义的任何东西都是世界上最接近的。您可以将代码的最终结果映射为等效于此:

function() {
    function bar() { ... }
    function quux() { ... }
}
// bar and quux are out of scope here :(

如果您希望将这些功能提供给全世界,您将需要一些对象来附加这些功能。 window是最便宜的,或类似的东西更好一点:

var myScope = {};
['bar', 'quux'].forEach(function(i) {
    eval('myScope["'+i+'"] = function(param) { this.param = param; return this; }');
});
myScope.bar();  // woo hoo!

答案 1 :(得分:1)

['bar', 'quux'].forEach(function(i) {
    this.eval('function '+i+'(param) { this.param = param; return this; }');
});

['bar', 'quux'].forEach(function(i) {
    window.eval('function '+i+'(param) { this.param = param; return this; }');
});

['bar', 'quux'].forEach(function(i) {
  eval.call(null, 'function ' + i + '(param) { this.param = param; return this; }');
  // same
  // eval.call(window, 'function ' + i + '(param) { this.param = param; return this; }');
});

答案 2 :(得分:1)

forEach的问题是eval在匿名函数内运行,因此创建的变量将被限制在该范围内,无法从外部访问。

要修复它,只需以不需要包装功能的其他方式迭代您的数组。例如:

  • for循环:

    var names = ['bar', 'quux'];
    for(var i=0; i<names.length; ++i)
        eval('function '+names[i]+'(param) { this.param = param; return this; }');
    
  • for...of(ECMAScript 6)

    for(var i of ['bar', 'quux'])
        eval('function '+i+'(param) { this.param = param; return this; }');
    

请注意,这不会在严格模式下工作:

  

10.4.2.1严格模式限制

     

eval代码无法实例化变量或函数绑定   调用eval if的调用上下文的变量环境   调用上下文的代码或eval代码是strict code。相反,这样的绑定在新的实例化中   VariableEnvironment只能通过评估代码访问。

答案 3 :(得分:0)

您可以简单地将功能分配给全局对象:

['bar', 'quux'].forEach(function(i) {
    eval('window.' + i + ' = function(param) { this.param = param; return this; }');
});

答案 4 :(得分:0)

还有一个答案!使用window对象:

['bar', 'quux'].forEach(function(i) {
    eval('window.'+i+' = function(param) { this.param = param; return this; }');
});