ES6箭头函数作用域的问题
在看阮一峰老师的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
一次都没更新。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
执行的时候作用域已经是全局作用域啦。
要想s2也改变,可以这样
我这里结合 JavaScript 的运行机制简单说一下。 setInterval 属于 webapi 范畴,当执行到函数内部的它时,不能直接被压入 stack 中, 会被放到 webapis 中等待执行,随后被放到 task queue 中。stack为空时,才会被压入 stack 中。这样你应该就能明白 “指向运行时所在的作用域” 所说的作用域是哪一块了。
1、箭头函数有作用域(词法作用域),词法作用域简单来讲就是,一切变量(包括this)都根据作用域链来查找。
2、箭头函数中的this因为绑定了词法作用域,所以始终指向自身外的第一个this(由于自身没有声明this,所以会去作用域链上找this),也就是始终等于调用它的函数的this(以为这个this离它最近)。
箭头函数没有自己的作用域,其作用域来自其父作用域。如果其父级还是个箭头函数,就继续往上找,直到根作用域为止。
就记住上面加粗的这句话就行了。这是 ES6 的规定,至于为什么这么规定,ECMA 组织没说。
正因如此,箭头函数内部访问
this
、super
、arguments
、new.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
其实这个是闭包和作用域的问题 ...
2边的 this 指向的作用于都不一样
箭头函数(()=>)是没有自己的作用域的,
标准函数(function)的作用域指向自己
如果还不明白就想想构造函数的 this 和 全局的 this(window)