JavaScript的this

原文:this in JavaScript

this关键字,也称为函数的“上下文”或“范围”,是一个强大的也令人迷惑的概念。本文帮你捋清思路。

this关键字可以引用函数的“执行上下文”。一个巧妙的说法是,this指向了调用函数所属的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// `this`是函数的隐性参数
const fn = function() {
return this;
};

// 设置`this`的一种方法,是将函数附加到对象中
const obj1 = { fn };
const obj2 = { fn };

obj1.fn() === obj1; // true
obj1.fn() === obj2; // false

obj2.fn() === obj1; // false
obj2.fn() === obj2; // true

需要重点关注的是,JavaScript的函数也是普通的变量,this是可以改变的。一个常见的搞混this的场景:把函数赋给一个对象,但调用函数时不用对象调用。这种俗称函数“丢失上下文”

1
2
3
4
5
6
7
8
9
10
const fn = function() {
return this;
};

const obj = { fn };

// 如果不用属性访问符`.`调用`fn()`
// 就是隐式的将函数上下文设为`null`
const myFn = obj.fn;
myFn() == null; // 严格模式下为true

简言之:this是函数调用时的隐性参数,当属于某个对象的函数调用时,this就是这个对象。

在ES6的类方法中,经常能见到this。在一个类方法中,this指向了调用方法所属的对象实例。

1
2
3
4
5
6
7
8
9
class MyClass {
myFunction() {
return this;
}
}

const obj = new MyClass();

obj.myFunction() === obj; // true

箭头函数

箭头函数不同于其他函数,它属于词法上下文。这意味着无论是以何种方式调用箭头函数,箭头函数中的this与箭头函数外的保持一致。

1
2
3
4
5
6
7
8
9
10
const arrow = () => this;

arrow() == null; // true

const obj = { arrow };

// 即使`arrow()`绑定到一个对象
// 它依然与上下文有相同的`this`
obj.arrow() == null; // true
obj.arrow() == this; // true

bind()、call()和apply()

每个JavaScript函数都有Function#call()函数Function#apply()函数,可以不必绑定对象就能指定this的值。call()apply()将隐性参数this变成了显性参数。

另外Function#bind()函数可以创建一个预设this的函数副本。

1
2
3
4
5
6
7
8
9
10
11
12
const fn = function() {
return this;
};

const obj = {};

fn.call(obj) === obj; // true
fn.apply(obj) === obj; // true

const copy = fn.bind(obj);
copy() === obj; // true
copy === fn; // false