this 指向
this关键字的值指向的其实是当前执行上下文(Execution context)。
而执行上下文分为三种——全局执行上下文(Global execution context)、函数执行上下文(Functional execution context)和eval执行上下文(Eval),每种上下文中都对应着一种this。
由于eval使用极少,下面只讲解全局执行上下文和函数执行上下文中的this。
全局执行上下文中的this
直接在控制台执行console.log(this),打印出来的就是全局执行上下文中的this,最终输出的是window对象。
由此,我们可以得出一个结论——全局执行上下文中的this指向window对象。
函数执行上下文中的this
函数执行上下文中的this指向取决于函数调用的方式,如果是作为普通函数执行,则this指向window对象。如果作为对象属性调用则指向对象本身。
执行以下代码:
function foo(){
console.log(this)
}
foo() //window
2
3
4
最终输出的还是window对象。那么再看下面一段代码:
const obj = {
foo () {
console.log(this);
}
};
obj.foo(); // obj
2
3
4
5
6
7
此时this指向的是obj对象而不是window。那么为什么同样都是函数调用,作为对象属性调用就会指向对象本身呢?
虽然上面代码对象是以字面量形式声明,但我们知道其实它相当于使用new方法创建了Object实例,而执行new指令会进行以下操作:
- 创建一个空的简单JavaScript对象(即**
{}**); - 为步骤1新创建的对象添加属性**
__proto__**,将该属性链接至构造函数的原型对象 ; - 将步骤1新创建的对象作为**
this**的上下文 ; - 如果该函数没有返回对象,则返回**
this**。
可以通过以下代码来理解:
function excuteNew (fn, ...args) {
let obj = Object.create(fn.prototype);
let res = fn.applay(obj, args);
return typeof res === 'object' ? res : obj;
}
2
3
4
5
可以看到其实是因为new内部修改了this的指向,所以才能指向对象本身。
看到这里就基本了解了函数中this的指向问题,结合上面分析下以下代码:
var myObj = {
name : "myobj",
showThis: function(){
console.log(this)
function bar(){console.log(this)}
bar()
}
}
myObj.showThis()
2
3
4
5
6
7
8
9
首先执行myObj.showThis(),此时showThis作为对象属性调用,所以第一个this应该打印的myObj。执行到内部bar函数时,此时bar虽然在myObj.showThis中执行,但它依旧是作为普通函数被调用,所以第二个打印的是window。
箭头函数中的this指向
箭头函数与普通函数不太一样,因为箭头函数并没有自己的this,它内部的this就是其外层代码块中的this,我们来分析下以下代码:
var a = 'global';
var obj={
a: 'inner',
bar () {
var bar = () => {
console.log(this.a);
};
return bar;
},
foo () {
console.log(this.a);
var foo = () => {
console.log(this.a);
};
foo();
}
};
obj.foo(); // inner, inner
var foo = obj.foo;
foo(); // global, global
obj.bar()(); // inner
var bar = obj.bar();
bar(); // inner
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
执行obj.foo时,内部this指向自身,而内部foo中的this就是外部的this,所以此时内部foo中this也指向obj。而将obj.foo赋值给变量foo再执行foo,此时foo作为普通函数执行,内部this指向window,所以此时内部foo中的this也指向window。这里要注意,this的指向是在代码执行时才确定的。
上面的解释可能有点难懂,其实通过babel转换成ES5语法就一目了然了,转换后的代码如下:
var a = 'global';
var obj = {
a: 'inner',
bar() {
var _this = this;
var bar = function () {
console.log(_this.a);
};
return bar;
},
foo() {
var _this2 = this;
console.log(this.a);
var foo = function () {
console.log(_this2.a);
};
foo();
}
};
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
其实就相当于使用了一个变量保存了父级函数的this。
总结
- 当函数作为对象的方法调用时,函数中的
this就是该对象; - 当函数被正常调用时,在严格模式下,
this值是undefined,非严格模式下this指向的是全局对象window; - 箭头函数的
this指向外层代码块的this;
