间隔永远不会停止......谁能解释一下?
被困在闭包范围内的变量是其原因,以下代码将在将 o 设置为 null 的同一范围内使用变量 o。
注意:我更喜欢使用闭包创建者来限制范围并防止其他意外。以下将在运行时创建闭包以保持代码简单。
var o = {};
setTimeout(function(){//closure accessing o directly
console.log("why is o null here:",o);
},100);
o=null;
以下代码将使用 o 作为传递的 o,传递的 o 现在被困在创建的闭包范围内,并且将 o 设置为 null 不会影响传递的 o。变异 o (o.something=22) 会影响传递的 o。(谷歌“javascript by reference by value”供参考)
var o = {};
setTimeout((function(o){
return function(){//closure accessing passed o
console.log("why is o not here:",o);
};
}(o)),100);
o=null;
要解决循环中创建闭包的常见问题,请将变量 (i) 传递给返回闭包的函数
for(var i = 0;i<10;i++){
setTimeout((function(i){
return function(){//not using i in the for loop but the passed one
console.log("and i is:",i);//0 to 9
};
}(i)),100);
}
因为将 i 变量与闭包在同一范围内会给您带来不想要的结果:
for(var i = 0;i<10;i++){
setTimeout(function(){
console.log("and i is:",i);//10 times and i is: 10
},100);
}
为什么periodic.go="" 起作用与通过引用传递值有关。下面的代码显示了它是如何工作的:
function test(o){
o=22;//no mutation but an assignment
}
var o = {name:"me"};
test(o);
console.log(o);//Object { name="me" }
function test2(o){
o.name="you";//mutates
}
test2(o);
console.log(o);//Object { name="you"}
怎么解决
我已经稍微更改了您的代码,以利用共享成员的原型(go 函数)并创建闭包以确保闭包的范围仅限于您实际需要的范围。
有关更多详细信息,请阅读构造函数和 this 变量的介绍。
function MyInterval(){//capitalize constructor
this.name = 'Paul';
this.doContinue = true;
this.timeoutid = false;
};
MyInterval.prototype.closures ={//creates closures with limited scope
//closure for the go function setting the invoking object
go:function(me){
return function(){
console.log("In go, name is:",me.name);
me.go();
//de reference "me", we no longer need it
// can't do this in a setInterval though
me=null;
};
}
}
MyInterval.prototype.go = function(){
if(this.constructor===MyInterval){
//if you were to call go multiple times
if(this.timeoutid)
clearTimeout(this.timeoutid);
//do it again if this.doContinue is true
this.timeoutid = (this.doContinue)? setTimeout(
this.closures.go(this)
//creates a closure function
,100
):false;
return;
};
console.log("this is not the correct value:",this);
};
//added stop, good call from shadow, now you can stop immediately
// or set doContinue to false and let it run it's course
MyInterval.prototype.stop = function(){
if(this.timeoutid)
clearTimeout(this.timeoutid);
this.timeoutid=false;
};
periodic = new MyInterval();
periodic.go();
//because the clearTimeout you can accedentally do something silly like:
periodic.go();
periodic.go();
setTimeout(function(){
periodic.name='George';
}, 150);
setTimeout(function(){
periodic.name ='John';
periodic.doContinue = false;
periodic.name = 'Ringo'
}, 250);