JavaScript setInterval没有正确绑定到正确的闭包
问题
嗨,大家好,我是JavaScript新手,我来自Python和Java的面向对象的世界,这是我的免责声明。
下面有两个代码块,替代实现,一个是JavaScript,一个是Coffeescript。 我想在Meteor.js应用程序的服务器上运行它们。 我遇到的问题是当使用绑定方法“this.printSomething”作为我的callback调用函数“setInterval”时,一旦执行该callback,它会丢失范围与实例导致“this.bar”未定义! 任何人都可以向我解释为什么JavaScript或coffescript代码不工作?
JavaScript实现
function Foo(bar) { this.bar = bar; this.start = function () { setInterval(this.printSomething, 3000); } this.printSomething = function() { console.log(this.bar); } } f = new Foo(5); f.start();
咖啡的实施
class foo constructor: (bar) -> @bar = bar start: () -> Meteor.setInterval(@printSomething, 3000) printSomething: () -> console.log @bar x = new foo 0 x.start()
您在setIntervalcallback中丢失了Foo
的上下文。 您可以使用Function.bind将上下文设置为像这样将callback函数引用的上下文设置回Foo
实例。
setInterval(this.printSomething.bind(this), 3000);
随着电话
setInterval(this.printSomething, 3000);
callback方法获取全局上下文(如果是租户,比如节点,则为web或全局窗口),所以你不会在那里获得属性bar
,因为this
是指全局上下文。
小提琴
要不就
this.printSomething = function() { console.log(bar); //you can access bar here since it is not bound to the instance of Foo }
你也可以尝试创build一个闭包来捕获this
。 喜欢这个:
var self = this; this.start = function () { setInterval(function(){ self.printSomething(); }, 3000); }
当你input一个函数,你会得到一个新的范围在JavaScript中。 您可以从父范围inheritance,但其值会更改。 在coffeescript中,你可以使用胖箭头(它看起来像是ecmascript 6的一部分),在进入新的范围之前基本上保留了this
引用。
class foo constructor: (bar) -> @bar = bar start: () => Meteor.setInterval(@printSomething, 3000) printSomething: () => console.log @bar x = new foo 0 x.start()
在javascript中处理这种事情的标准方法是在你想要引用的地方创build一个引用,然后在你的作用域调用中使用引用。
function Foo(bar) { // make reference to `this` at the point // where you want to use it from self = this; self.bar = bar; self.start = function () { setInterval(self.printSomething, 3000); } self.printSomething = function() { console.log(self.bar); } } f = new Foo(5); f.start();