【问题标题】:ES6 Arrow functions vs ES5: how to know which function to bind `this` to when using ES5 non-arrow functionES6 箭头函数 vs ES5:使用 ES5 非箭头函数时如何知道将 `this` 绑定到哪个函数
【发布时间】:2020-06-02 00:59:32
【问题描述】:

我正在阅读this article 使用 ES6 箭头函数。它给出了下面的例子,你必须使用bind(this),然后是相应的带有箭头函数的代码。

var obj = {
  id: 42,
  counter: function counter() {
    setTimeout(function() {
      console.log(this.id);
    }.bind(this), 1000);
  }
};

上面写着In the ES5 example, .bind(this) is required to help pass the this context into the function

我想知道的: 为什么你使用bind(this)setTimeout 的回调而不是counter 函数?即为什么上面的代码不是这样的:

var obj = {
  id: 42,
  counter: function counter() {
    setTimeout(function() {
      console.log(this.id);
    }, 1000);
  }.bind(this);
};

【问题讨论】:

    标签: javascript ecmascript-6 ecmascript-5 arrow-functions


    【解决方案1】:

    为什么你将bind(this)setTimeout 的回调一起使用,而不是与计数器函数一起使用?

    因为counter 函数(其工作方式类似于obj 对象的方法)已经具有正确的this,因为您将其称为obj.counter(),因此它通过将其称为obj.counter() 得到this .假设你将 counter 调用为obj.counter(),那么如果你在counter() 函数的第一行执行console.log(this.id),它将正确显示id 的值。

    您传递给setTimeout() 的回调没有自然的this 值,除非您在回调函数本身上使用箭头函数或.bind(),因为当setTimeout() 调用您的回调时,它不会设置特定的@987654338 @value(它只是将您的回调作为普通函数调用),因此 this 值变为默认值。这意味着如果运行严格模式,this 将是 undefined,如果在 setTimeout() 回调内以松散-goosey 模式运行,则为全局对象。

    查看调用函数时this的值设置here的6种方式。


    我还应该提到,如果你按照你的提议做了这样的事情:

    var obj = {
      id: 42,
      counter: function counter() {
        setTimeout(function() {
          console.log(this.id);
        }, 1000);
      }.bind(this);
    };
    

    它不仅对setTimeout() 回调没有任何帮助,而且还会将this 的错误值绑定到counter() 方法。您将得到 thisvar obj 定义之前的任何内容(也称为 this 的词法值)。

    【讨论】:

    • 可能值得一提的是,在对象中这样定义的函数通常称为方法。 Kinda 有助于更好地将其使用/范围与 IMO 结合起来
    • 知道了,谢谢!也感谢@Phil 的留言。
    • 其实等等,我还是不明白为什么在回调上使用bindthis的值设置为obj,而在counter上使用它设置为词法值.为什么不将其应用于counter 绑定counterobj
    • @gkeenley - 因为调用obj.counter() 已经将counter 内部的this 设置为obj。因此,当您将function() {}.bind(this)setTimeout() 一起使用时,它会获取this 的值(所需的值)。执行.bind(this) 来对抗自身,采用当时正在使用的this 值并将其设置为counter() 范围。这有两个问题。首先,这是 this 的错误值(不是 obj),其次,它控制了计数器范围,而不是您的问题所在的 setTimeout() 范围的回调。
    • 好了,一切都明白了。我很感激。