一、this关键字小测试
ES6箭头函数体中的this指向哪里?
在回答这个问题之前先来揣揣你对this
关键字的了解程度:
(让我们回到ES6之前)
题:
var obj = {
a: function() {
console.log(this);
}
}
var b = obj.a;
b();
问:打印出的this
的值?
再来几个选项:
window
obj
document
obj.a
答案是window
(可以在控制台运行一下)
什么!什么情况!发生了什么?
一句话解释:
一般的,this
指向函数运行(调用)时所在的执行环境【《JavaScript高级程序设计》4.2节执行环境及作用域】的(变量)对象(简单地,this
指向函数的调用者)
分析代码:
var b = obj.a; // ==>相当于
var b = function() {
console.log(this);
}
函数调用时(b();
)其所在的执行环境是全局环境,所以this
指向全局变量对象window
二、ES6箭头函数
如果你觉得以上这些都知道了(我会!我会!)那么就继续吧~~
(来到ES6箭头函数)
例1【阮一峰《ECMAScript 6 入门》-7.函数的扩展:箭头函数】
我将阮老师的例子代码修改了一下:
(普通函数)
function foo() {
console.log("id1:", this.id);
console.log("this1:", this);
setTimeout(function() {
console.log("id2:", this.id);
console.log("this2:", this);
}, 0);
}
var id = 21;
foo();
// Chrome
// id1: 21
// this1: window
// id2: 21
// this2: window
foo.call({id: 42});
// Chrome
// id1: 42
// this1: {id: 42}
// id2: 21
// this2: window
注意:超时调用(setTimeout
回调)的代码都是在全局作用域环境中执行的,因此(setTimeout
回调)函数中this
的值在非严格模式下指向window
对象,在严格模式下是undefined
例如
var obj = {
console.log(this);
setTimeout(function() {
console.log(this);
}, 0);
}
obj.a();
// Chrome
// {a: f}
// window
回到例1
我们使用foo
函数的call
方法改变了foo
函数调用时函数体内this
的指向({id: 42}
这个对象),但setTimeout
回调函数中的this依旧指向window
对象(因为在全局环境中运行)。
接下来再将例1改写一下,将foo
函数中的setTimeout
回调函数改成箭头函数的形式:
例2
(箭头函数)
function foo() {
console.log("id1:", this.id);
console.log("this1:", this);
setTimeout(() => {
console.log("id2:", this.id);
console.log("this2:", this);
}, 0);
}
var id = 21;
foo();
// Chrome
// id1: 21
// this1: window
// id2: 21
// this2: window
foo.call({id: 42});
// Chrome
// id1: 42
// this1: {id: 42}
// id2: 42
// this2: {id: 42}
foo();
的输出结果没有变化,但foo.call({id: 42});
的输出结果改变了。
到底发生了什么?
在这里直接给出结论:
箭头函数根本没有自己的this
,导致内部的this
指向了外层代码的this
,这个指向在定义时就已经确定而不会在调用时指向其执行环境的(变量)对象。
注意:因为箭头函数内部的this
是指向外层代码块的this
(最近的this
,例2中的foo函数)的,所以我们可以通过改变外层代码块的this
的指向从而改变箭头函数中this
的指向(例2中使用了foo
函数的call
方法)。
重新解释例2
因为箭头函数(setTimeout
回调)没有自己的this
,导致其内部的this
引用了外层代码块的this
,即foo
函数的this
,
(要注意:在定义阶段(调用函数前),foo
函数的this
的值并不确定【《JavaScript高级程序设计》第三版5.5.4函数内部属性】,但箭头函数的this
自定义阶段开始就指向foo
函数的this
了)
又因为使用call
方法改变了foo
函数运行(调用)时其函数体内this
的指向(重新指向对象{id: 42}
)从而使箭头函数中this
的指向发生变化,最后输出例2所示结果。
三、例子总结
到这里,我想小伙伴们应该是比较清楚了,那么不妨去看看阮一峰老师的《ECMAScript 6 入门》函数的扩展一节箭头函数部分的一个问题示例:“请问下面的代码中有几个this(滑稽)”
加深印象
例3【阮一峰《ECMAScript 6 入门》-19.Class基本语法:this的指向】
class Logger {
constructor() {
this.printName = (name = 'there') => {
this.print(`Hello ${name}`);
};
}
// ...
}
箭头函数中的this
指向constructor
构造方法内部的this
,由于此时constructor
中的this
尚未获得值,当通过new
命令生成对象实例时,将会自动调用constructor
方法,constructor
的this
才能指向该实例对象,在此过程中,箭头函数中的this
一直引用着constructor
中的this
,当constructor
中this
发生变化,箭头函数的this
也会一并发生变化。
若有错误,请指出批评!!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。