javascript中具有作用域的SetInterval
您需要使用或重新分配上下文,因为以这种方式调用的函数会将其上下文丢失到全局范围。这在下面的示例中最容易观察到javascript中具有作用域的SetInterval,javascript,Javascript,您需要使用或重新分配上下文,因为以这种方式调用的函数会将其上下文丢失到全局范围。这在下面的示例中最容易观察到 var i=0; var t={ a:function(){ var that=this; this.timer=setInterval(function(){ that.b(); },30); }, b:function(){ if(i++<1){ console.log(this); } } };
var i=0;
var t={
a:function(){
var that=this;
this.timer=setInterval(function(){
that.b();
},30);
},
b:function(){
if(i++<1){
console.log(this);
}
}
};
t.a();
以下是您案例中的一些解决方案示例
o = { // an object
foo: 1,
bar: function () { // function assuming `this` is `o`
return this.foo;
}
};
f = o.bar; // function `f` loses scope of `o`
o.bar(); // 1, o.foo is defined
f(); // undefined, window.foo is undefined
在这些示例中,您将此作为第三个参数传递,即
// bind
function scopedInterval(func, delay, context) {
return window.setInterval(func.bind(context), delay);
}
// or call
function scopedInterval(func, delay, context) {
return window.setInterval(function () {func.call(context);}, delay);
}
如果不这样做,setInterval
的上下文是window
(我总是将其作为window.setInterval
调用,所以我不会忘记这一点)正如Crockford在他的新书《Javascripts:好的部分》中所说:
当函数不是对象的属性时,它将作为函数调用[这是setInterval的情况]。使用此模式调用函数时,“this”绑定到全局对象。这是语言设计中的一个错误。如果语言设计正确,当调用内部函数时,“this”仍将绑定到外部函数的“this”变量。此错误的结果是,方法无法使用内部函数来帮助其完成工作,因为内部函数不共享方法对对象的访问权限,因为其“this”绑定到错误的值。[然后他谈到与你发现的相同的解决方法]
你想知道为什么这不起作用是对的,对我来说,所有其他答案都不能正确地解决这个问题。事实上,这是毫无意义的,正如Crockford所说,这是语言设计中的一个错误,可能会让人感到困惑 所以如果你知道如何解决这个问题。。。你为什么要问?@migg我想知道为什么:)请不要把上下文(thisArg的thisArg
)与[variable]作用域混淆。这并不能解释为什么。这是因为它是language@Geeo我不能+1你回答的唯一原因是(正如你在评论中重复的)你说“这是语言的一个缺陷”。这是一种观点,而我同意JavaScript有一个愚蠢的定义,即<代码> < < /> >在这些情况下应该如何工作,它可能会“打扰人”,我不认为它是“bug”。顺便说一下,它比“代码> >调用<代码>在本例中要简单得多:只是代码>上下文。函数()(代码)> @ PaulS。是的,这不是一个真正的错误,仍然是一个糟糕的设计。谢谢,我还没有读那本书,我会完成阅读惊人的书的时候!Crockford正确地指出,此
不应引用全局对象,但是我认为如果这个
引用函数实例化时在词汇封闭范围内的任何内容,会引起各种各样的奇怪。@Pointy你能详细解释一下你为什么这么认为吗?@Geeo我得花点时间考虑一下,但它在我的脑海中敲响了警钟:-)我知道,在未来的语言版本中,有些情况下会出现这种情况(我认为是“和谐”)。
// bind
function scopedInterval(func, delay, context) {
return window.setInterval(func.bind(context), delay);
}
// or call
function scopedInterval(func, delay, context) {
return window.setInterval(function () {func.call(context);}, delay);
}
this.timer = scopedInterval(this.b, 30, this);