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
;