【问题标题】:Scope of arrow function vs es5 function in setTimeoutsetTimeout 中箭头函数与 es5 函数的范围
【发布时间】:2019-08-23 13:14:15
【问题描述】:

我正在试验 this 和箭头函数。 在 setTimeout 中箭头函数的词法范围遇到了一些问题。

makeSound 方法将 this 作为 dog 对象返回。由于箭头函数在 setTimeout 方法中,为什么它不占用全局对象的范围?有趣的是,whatIsThis 方法返回的是 Timeout 对象,而不是全局对象。我对此也感到困惑。

const dog = {
  name: 'fluffy',
  type: 'dog',
  sound: 'woof!',
  makeSound: function() {
    setTimeout(() => {
      console.log("makeSound", this)
    }, 1000)

  },
  whatIsThis: function() {
    setTimeout(function() {
      console.log("whatisthis", this)
    }, 1000)
  }
}


dog.makeSound() // returns dog obj
dog.whatIsThis() // returns Timeout obj


setTimeout(() => {
  console.log("global", this)
}, 1000) // returns global obj

【问题讨论】:

  • 你确定 dog.whatIsThis() 记录了 Timeout 对象。对我来说,它记录了窗口对象,这很有意义,因为您声明了一个由 setTimeout 调用的新词法范围。箭头函数从外部词法范围获取它的 this(在你的例子中是 makeSound,它等于 dog)。

标签: javascript ecmascript-6 this settimeout arrow-functions


【解决方案1】:

箭头函数在setTimeout方法内部,为什么不占用全局对象的作用域?

回调不在setTimeout 函数“内部”。它作为参数传递给setTimeout 函数。

考虑以下等效代码:

const dog = {
  name: 'fluffy',
  type: 'dog',
  sound: 'woof!',
  makeSound: function() {
    const cb = () => console.log("makeSound", this);
    setTimeout(cb, 1000)
  },
}

此代码的行为完全相同。唯一的区别是回调函数在传递给setTimeout之前先分配给变量。

这应该表明箭头函数不在“内部”setTimeout,而是在makeSound 内部。箭头函数在词法上解析this,就像任何其他变量一样。所以我们要找出this里面makeSound的值是什么。为了找出答案,我们必须看看方法是如何被调用的。既然叫dog.makeSound(),那么this指的是dog

【讨论】:

    【解决方案2】:

    箭头函数被声明的范围是围绕它的函数的范围 (dog.makeSound),而不是箭头函数被传递到的函数。

    当你在makeSound 函数内部调用dog.makeSound() 时,this 指的是dog,因此它也在箭头函数内部这样做。

      // no matter what the surrounding is ...
      const that = this;
      /*no matter whats here*/(() => {
         console.log(that === this); // this will always be true
      })();
    

    有趣的是,whatIsThis 方法返回的是 Timeout 对象,而不是全局对象。我对此也感到困惑。

    我也是。这种行为很奇怪,您确定您没有误解控制台输出吗?

    【讨论】: