ES6箭头函数作用域的问题

如初
  • 65

在看阮一峰老师的ES6入门,在箭头函数那里有点不明白的

箭头函数this绑定定义时的作用域,这个好理解。
后者的this指向运行时所在的作用域(即全局对象)这是为什么?运行时不也在Timer()函数内部?为什么作用域变成全局的了?

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval(function () {
    this.s2++;
  }, 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1: 3
// s2: 0
上面代码中,Timer函数内部设置了两个定时器,分别使用了箭头函数和普通函数。前者的this绑定定义时所在的作用域(即Timer函数),后者的this指向运行时所在的作用域(即全局对象)。所以,3100 毫秒之后,timer.s1被更新了 3 次,而timer.s2一次都没更新。
回复
阅读 2.2k
8 个回答
function () {
    this.s2++;
}

执行的时候作用域已经是全局作用域啦。
要想s2也改变,可以这样

function Timer() {
  this.s1 = 0;
  this.s2 = 0;
  // 箭头函数
  setInterval(() => this.s1++, 1000);
  // 普通函数
  setInterval((function () {
    this.s2++;
  }).bind(this), 1000);
}

var timer = new Timer();

setTimeout(() => console.log('s1: ', timer.s1), 3100);
setTimeout(() => console.log('s2: ', timer.s2), 3100);
// s1 3
// s2 3

我这里结合 JavaScript 的运行机制简单说一下。 setInterval 属于 webapi 范畴,当执行到函数内部的它时,不能直接被压入 stack 中, 会被放到 webapis 中等待执行,随后被放到 task queue 中。stack为空时,才会被压入 stack 中。这样你应该就能明白 “指向运行时所在的作用域” 所说的作用域是哪一块了。

1、箭头函数有作用域(词法作用域),词法作用域简单来讲就是,一切变量(包括this)都根据作用域链来查找。

2、箭头函数中的this因为绑定了词法作用域,所以始终指向自身外的第一个this(由于自身没有声明this,所以会去作用域链上找this),也就是始终等于调用它的函数的this(以为这个this离它最近)。

箭头函数没有自己的作用域,其作用域来自其父作用域。如果其父级还是个箭头函数,就继续往上找,直到根作用域为止。

就记住上面加粗的这句话就行了。这是 ES6 的规定,至于为什么这么规定,ECMA 组织没说。

正因如此,箭头函数内部访问 thissuperargumentsnew.target 这几个特殊对象,都会去其父作用域里找。


可以看我以前的一个回答,更具体一些:https://segmentfault.com/q/10...

还是要好好理解 运行时作用域 这个概念。

箭头函数理解了,这里跳过不说。

单说这个普通函数。

因为 setInterval 会将回到函数放入 宏任务 中。简单的理解就是它是异步执行的,所以当它执行时, 它的执行环境其实是在 window 上的。
所以回调中的 this.s2 其实就是调用 window.s2

timer.s2 声明之后并没有被调用,当然是一次都没更新了。

普通函数执行时this的指向,和它的调用者有关。而 function () { this.s2++; } 没有调用者,this会默认指向全局对象,也就是window。

而箭头函数没有this,所以使用的是父作用域中的this,Timer作为构造函数,此时作用域中的this就是实例timer

(function () {
    this.s2++;
  })

其实这个是闭包和作用域的问题 ...
2边的 this 指向的作用于都不一样
箭头函数(()=>)是没有自己的作用域的,
标准函数(function)的作用域指向自己

如果还不明白就想想构造函数的 this 和 全局的 this(window)

你知道吗?

宣传栏