关闭JavaScript的立即评估

问题描述:

考虑下面的Javascript代码:关闭JavaScript的立即评估

var a = []; 

var f = function() { 

    for (var i = 0; i < 3; i++) { 
     a.push(function(){alert(i)}); 
    } 
    for (var j = 0; j < 3; j++) { 
     a[j](); 
    } 
}; 

警报打印出 '3' 的所有三次。我想要一个不同的行为 - 在循环的每次迭代中生成一个打印i的当前值的函数。即3个功能可以打印不同的索引。

任何想法?

+0

只是添加这个是因为Javascript没有块范围的唯一功能范围的概念,这也抛出了我... http://www.mattfreeman.co.uk/2010/03/closures-scope-in​​- javascript-vs-c/ – 2010-05-21 08:07:30

创建它接受i作为参数,并返回一个特定功能的匿名函数:

for (var i = 0; i < 3; i++) { 
    a.push((function(i) { 
     return function() { 
      alert(i); 
     } 
    })(i)); 
} 

for (var j = 0; j < 3; j++) { 
    a[j](); 
} 

或者做类似的事情:建立它接受i作为参数传递给函数添加到阵列的匿名函数:

for (var i = 0; i < 3; i++) { 
    (function(i) { 
     a.push(function() { 
      alert(i); 
     }); 
    })(i); 
} 

for (var j = 0; j < 3; j++) { 
    a[j](); 
} 
+1

不是它的必需条件,但我认为它看起来更清晰,并且描述了你的意图,以便更好地在'()' - >'(function(i){...} )(i);' – gnarf 2009-09-12 01:18:51

+0

@gnarf,我自己正在辩论。我想它确实使意图更清楚。我将编辑它。 – strager 2009-09-12 01:20:57

+0

这似乎是通过提供一种不存在同样的潜在缺陷的替代解决方案来解决原始问题......您在这里做的是将值推入数组中。原来的海报推动功能,我们认为,这将在稍后的时间执行...... – Funka 2009-09-12 01:35:46

var iterate = (function() { 
    var i, j = []; 
    for (i = 0; i < 3; i += 1) { 
     j.push(i); 
     alert(j[j.length - 1]); 
    } 
}()); 

您不必封仅仅输出值。但是,您的代码应该包含在面向对象遏制的函数中。函数不必被调用来执行。

+0

”不必调用函数来执行。“什么?这种说法不是很清楚,因为这听起来不对。澄清,拜托? – strager 2009-09-12 01:13:45

+0

为了执行一个功能必须发生三件事情之一。 1)函数必须由正在执行的其他名称调用。 2)该函数可以被插入到一个方法中,在这种情况下该函数可以是匿名的并且仍然可以被执行。我强烈反对使用函数而不给它们命名。 3)函数可以在它们被解释时完全独立执行,如果它们在右括号之后用括号终止,如}()。这被称为即时召唤。 – 2009-09-12 01:24:14

+0

我不同意。在Javascript中,函数是一个值类型,就像'42'或''hello world''一样。无论它是分配给变量还是直接使用都没有什么特别的。对于这种行为的例子,运行:'(function(i){var func = arguments.callee; if(!i)return; console.log('x'); window.setTimeout(function(){func(i - '0123)(4);' – strager 2009-09-12 01:31:10

功能(我){警报(我)

+2

很可能,'i'将会是未定义的。 – strager 2009-09-12 01:10:42

+0

+1简洁。如果 a.push(function(i){alert(i)});使用 代替 a.push(function(){alert(i)}); – 2014-01-18 15:13:23

只是另一种方法,使用currying

var a = []; 
var f = function() { 
    for (var i = 0; i < 3; i++) { 
     a.push((function(a){alert(a);}).curry(i)); 
    } 
    for (var j = 0; j < 3; j++) { 
     a[j](); 
    } 
}; 

// curry implementation 
Function.prototype.curry = function() { 
    var fn = this, args = Array.prototype.slice.call(arguments); 
    return function() { 
    return fn.apply(this, args.concat(
     Array.prototype.slice.call(arguments))); 
    }; 
}; 

检查上面的代码运行here

+1

咖喱好用 - 虽然现在我很饿.... – gnarf 2009-09-12 01:59:09

+0

哇。棒极了。 +1。 – strager 2009-09-12 02:15:29

你可以把你的循环体中的匿名函数:

var a = []; 

for(var i = 0; i < 3; i++) (function(i) { 
    a.push(function() { alert(i); }); 
})(i) 

for(var j = 0; j < 3; j++) { 
    a[j](); 
} 

通过创建功能和传递的“我”作为参数,我们正在创造一个新的“我”变循环的价值在基本隐藏外部“我”的循环体内。现在您将数组放入数组中,可以看到新变量,其值在第一个循环中调用外函数函数时设置。如果我们使用不同的名称,当我们创造了新的变量,这可能是更清楚...这做同样的事:

var a = []; 

for(var i = 0; i < 3; i++) (function(iNew) { 
    a.push(function() { alert(iNew); }); 
})(i) 

for(var j = 0; j < 3; j++) { 
    a[j](); 
} 

“INEW”的值赋给0,然后1,然后2,因为该功能被循环立即调用。