JavaScript 中的 this
是一个繁琐的概念,但是大致可以分为以下五种:
- 全局环境下的
this
, 例如函数的直接调用; - 上下文中的
this
, 例如调用对象中的函数,类中。 call
,apply
,bind
绑定this
;- 构造函数下的
this
.
上述四者的优先级从低到高,且
this
均为在执行时确定的。
- 箭头函数中的
this
, 箭头函数中的this
是在定义时确定的。
作为示例,观察下列函数的在不同环境下的输出。
function consoleThis() {
console.log(this);
}
直接执行函数时 this
指向全局,例如:
// 直接执行(非严格模式下)
consoleThis() // global or window 对象
当然,在严格模式下,指向的为 undefined.
function consoleThis2() {
'use strict'
console.log(this);
}
consoleThis2() // undefined
例如:
const p = {
name: 'mike',
consoleThis,
brother: {
name: 'lucas',
consoleThis
}
}
p.consoleThis() // {name: 'mike', consoleThis: Function, brother: Object}
p.brother.consoleThis() // {name: 'lucas', consoleThis: Function}
在 class
中:
class p2 {
consoleThis = consoleThis
}
(new p2()).consoleThis(); // p2 { consoleThis: [Function: consoleThis] }
// 指向该类
例如:
consoleThis2.call(p.brother.name) // lucas
更多关于
call
,apply
,bind
区别的内容可见:JavaScript 中 call, apply, bind 的原理与实现
例如:
function person() {
this.name = 'jack'
}
console.log((new person()).name) // jack
// 这证明了 new 生成的实例指向一个对象
下面,考虑 new 一个函数时发生什么:
- 构造一个对象;
- 将
this
指向该对象; - 为该对象增加方法、属性;
- 返回该对象。
关于 ES6 的 class 可以参考:JavaScript中的继承
同时,当构造函数存在显式的 return
时,需要注意两种情况:
- 返回的是构造函数内部的对象:
function person2() {
this.name = 'penny';
const obj = {};
return obj;
}
console.log(new person2()) // {}, 表明返回 obj.
- 返回的是非对象的值:
function person3() {
this.name = 'tom';
return 1;
}
console.log(new person3()) // {name: 'tom'}, 表明返回目标对象的实例 this
ES6 中的箭头函数有一个关键的特性:它的 this
是静态的(在定义函数时就已经绑定),例如,在 指向上下文的 this 中,如果将 p.brother.consoleThis2 更改为箭头函数,会将其指向外层:
const a = () => {
console.log(this)
}
const arrowP = {
name: 'mike',
consoleThis() {
return this;
},
brother: {
name: 'lucas',
consoleThis: () => {
return this;
}
}
}
console.log(arrowP.consoleThis())
// {name: 'mike', consoleThis: Function, brother: Object}, 指向当前对象
console.log(arrowP.brother.consoleThis())
// {}, 等价于 a() 的返回结果
console.log(a())
// {}
由于 箭头函数中 this
的静态性质,导致它不能当作构造函数。
更多箭头函数的内容可以参考:ES6 中的箭头函数