大家好,我是JavaScript的新手,我来自面向对象的Python和Java世界,这是我的免责声明。
下面有两个代码块,替代实现,一个在JavaScript中,一个在Coffeescript中。我试图在Meteor.js应用程序中的服务器上运行它们。我遇到的问题是当使用bound-method“this.printSomething”作为我的回调函数调用函数“setInterval”时,一旦执行了回调,它就会丢失范围,导致“this.bar”未定义!任何人都可以向我解释为什么JavaScript或coffescript代码不起作用?
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()
答案 0 :(得分:2)
您在setInterval回调中丢失了Foo
的上下文。您可以使用Function.bind将上下文设置为类似的内容,以将回调函数引用的上下文设置回Foo
实例。
setInterval(this.printSomething.bind(this), 3000);
通过电话
setInterval(this.printSomething, 3000);
回调方法获取全局上下文(如果是租户,例如节点,则为Web或全局的窗口),因此您不会获得属性bar
,因为this
指的是全局上下文。
<强> Fiddle 强>
或只是
this.printSomething = function() {
console.log(bar); //you can access bar here since it is not bound to the instance of Foo
}
答案 1 :(得分:1)
您还可以尝试创建一个闭包来捕获this
。像这样:
var self = this;
this.start = function () {
setInterval(function(){
self.printSomething();
}, 3000);
}
答案 2 :(得分:0)
当您输入一个函数时,您将在javascript中获得一个新范围。您可以从父作用域继承,但this
的值会更改。在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中处理此类事情的标准方法是在您要引用的位置创建对this
的引用,然后在超出范围的调用中使用该引用...
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();