javascript闭包即时评估
考虑以下Javascript代码:javascript闭包即时评估,javascript,loops,closures,scope,Javascript,Loops,Closures,Scope,考虑以下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](); } }; var a=[]; var f=函数(){ 对于(变量i=0;i
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]();
}
};
var a=[];
var f=函数(){
对于(变量i=0;i<3;i++){
a、 push(函数(){alert(i)});
}
对于(var j=0;j<3;j++){
a[j]();
}
};
警报三次打印出“3”。我想要一个不同的行为-在循环的每次迭代中生成一个打印当前I值的函数。即3个打印不同索引的函数
有什么想法吗?创建一个匿名函数,它接受
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]();
}
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 iterate=(函数(){
var i,j=[];
对于(i=0;i<3;i+=1){
j、 推(i);
警报(j[j.length-1]);
}
}());
您不需要闭包来仅仅输出一个值。但是,您的代码应该包含在面向对象包含的函数中。不必调用函数即可执行。函数(i){alert(i)只是另一种方法,使用:
var a=[];
var f=函数(){
对于(变量i=0;i<3;i++){
a、 push((函数(a){alert(a);}).curry(i));
}
对于(var j=0;j<3;j++){
a[j]();
}
};
//咖喱执行
Function.prototype.curry=函数(){
var fn=this,args=Array.prototype.slice.call(参数);
返回函数(){
返回fn.apply(此参数为args.concat(
Array.prototype.slice.call(参数));
};
};
检查上面正在运行的代码段。您可以将循环主体放入匿名函数中:
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]();
}
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=[];
对于(var i=0;i<3;i++)(函数(i){
a、 push(函数(){alert(i);});
})(一)
对于(var j=0;j<3;j++){
a[j]();
}
通过创建该函数并将循环的值“i”作为参数传递,我们在循环体内部创建了一个新的“i”变量,该变量本质上隐藏了外部的“i”。您推到数组上的闭包现在会看到新变量,该变量的值在第一个循环中调用外部函数时设置。如果在创建新变量时使用不同的名称,这可能会更清楚…这与此相同:
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]();
}
var a=[];
对于(变量i=0;i<3;i++)(函数(iNew){
a、 push(函数(){alert(iNew);});
})(一)
对于(var j=0;j<3;j++){
a[j]();
}
“iNew”的值被分配为0,然后是1,然后是2,因为循环会立即调用该函数。更有可能的是,
i
将是未定义的。+1用于简洁性。如果使用a.push(function(i){alert(i)});而不是a.push(function(){alert(i)});“不必调用函数即可执行。”什么?那句话不太清楚,而且听上去是错的。请澄清一下?为了执行一个函数,必须发生以下三件事之一。1)函数必须由其他正在执行的对象按名称调用。2)函数可以插入到方法中,在这种情况下,函数可以是匿名的,并且仍然可以执行。Itrongly反对在不给函数命名的情况下使用函数。3)函数可以完全独立执行,因为如果它们在结束括号后用括号终止,例如}()。这就是所谓的即时唤起。我不同意。函数是一种值类型,就像Javascript中的42
或'hello world'
。无论它是否被分配给变量或直接使用,都没有什么特别的意义。对于此行为的示例,请运行:(函数(i){var func=arguments.callee;if(!i)return;console.log('x');window.setTimeout(函数(){func(i-1);},1000);})(4)
@austin:我非常反对“我强烈反对使用函数而不给它们命名”这句话——匿名函数是javascript忍者系列中最有用的工具之一。总是给函数命名有很多好处。1) 匿名函数与即时调用函数的作用完全相同,只是可以在少数地方使用。2) 命名函数使文档的编写变得更加简单和详细。3) 命名函数为单元测试提供了一个已知位置,在使用匿名函数时,某些位置不是唯一已知的。因此,始终命名函数有很大的好处,而不命名函数则没有好处。这并不是必需的,但我认为它看起来更简洁,并且更好地描述了将“立即执行”的函数包装在()
->(函数(I){…})(I)中的意图代码>@gnarf,我自己也在争论这个问题。我想这确实让意图更清楚了。我将在中对其进行编辑。这似乎通过提供一种不易受相同潜在缺陷影响的替代解决方案来回避原始问题。。。这里要做的是将值推送到数组上。最初的海报是推送功能,我们推测,这些功能将在稍后的某个时间执行……对不起,我评论得太快了。你说得对。另请参阅我的答案,以获得相同问题的类似解决方案。@funka-您仍然推送函数:创建(函数(i){
作用域变量i
,以保持函数被调用时的状态。使用})(i)
然后立即调用该新函数,并将i
作为参数,该参数返回一个函数。。。有效地将[function(){alert(0);},function(){alert(1);},function(){alert(2);}]
存储在a
中,很好地使用了咖喱-虽然现在我很饿…只是补充一下,这是因为Javascript没有块作用域的概念,只有函数作用域,这也让我很失望。。。
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]();
}