1

问题

大家好,我对 JavaScript 相当陌生,我来自 Python 和 Java 非常面向对象的世界,这是我的免责声明。

下面有两块代码,替代实现,一个在 JavaScript 中,一个在 Coffeescript 中。我正在尝试在 Meteor.js 应用程序的服务器上运行它们。我遇到的问题是当使用绑定方法“this.printSomething”作为我的回调调用函数“setInterval”时,一旦执行该回调,它就会失去实例的范围,导致“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();

Coffeescript 实现

class foo
    constructor: (bar) ->
        @bar = bar

    start: () ->
        Meteor.setInterval(@printSomething, 3000)

    printSomething: () ->
        console.log @bar

x = new foo 0
x.start()
4

3 回答 3

2

Foo在 setInterval 回调中丢失了上下文。您可以使用Function.bind将上下文设置为类似这样的内容,以便将回调函数引用设置回Foo实例的上下文。

setInterval(this.printSomething.bind(this), 3000);

随着通话

setInterval(this.printSomething, 3000);

回调方法获取全局上下文(在 web 的情况下为窗口,在节点等租户的情况下为全局),因此您不会在此处获取属性bar,因为它this指的是全局上下文。

小提琴

要不就

 this.printSomething = function() {
     console.log(bar); //you can access bar here since it is not bound to the instance of Foo
  }
于 2013-09-11T03:11:40.143 回答
1

您也可以尝试创建一个闭包来捕获this. 像这样:

var self = this;
this.start = function () {
    setInterval(function(){
       self.printSomething();
    }, 3000);
}
于 2013-09-11T03:22:02.110 回答
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();
于 2013-09-11T07:45:25.650 回答