【问题标题】:JavaScript setInterval not being properly bound to correct closureJavaScript setInterval 没有正确绑定到正确的闭包
【发布时间】:2013-09-14 22:28:25
【问题描述】:

问题

大家好,我是 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();

咖啡脚本实现

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

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

    printSomething: () ->
        console.log @bar

x = new foo 0
x.start()

【问题讨论】:

    标签: javascript node.js coffeescript meteor


    【解决方案1】:

    您在 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
      }
    

    【讨论】:

    • 而且,对于CoffeeScript,函数可以绑定the "fat arrow" -- printSomething: () =>
    • @JonathanLonowski 谢谢...不熟悉咖啡语法。 :)
    【解决方案2】:

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

    var self = this;
    this.start = function () {
        setInterval(function(){
           self.printSomething();
        }, 3000);
    }
    

    【讨论】:

      【解决方案3】:

      当你输入一个函数时,你会在 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();
      

      【讨论】:

        猜你喜欢
        • 2018-08-09
        • 1970-01-01
        • 2019-07-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-14
        • 1970-01-01
        • 2015-09-08
        相关资源
        最近更新 更多