如何动态创建不考虑范围的命名函数



这有效:

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功能是否在期间可用,但它在外面无法生存。

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!
['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; }');
});

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 if 的调用上下文的变量环境 调用上下文的代码或评估代码是严格的 法典。相反,此类绑定在新的 只有评估代码才能访问的变量环境。

您可以简单地将函数分配给全局对象:

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

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

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

最新更新