摘要
- 三种方法均可改变函数
this关键字的指向。apply()接受一参数数组,返回函数执行的结果。call()接受一组参数,返回函数执行的结果。bind()接受一组参数,返回函数体。需在bind()后加小括号才能执行函数。- 箭头函数的
this绑定后无论使用apply()、call()还是bind()都不可修改。
浅析this关键字
- JavaScript中的函数存在
定义上下文和运行上下文,通过call()、apply()和bind()可以改变this的指向。this总指向运行上下文。
定义上下文
定义上下文更准确的名称应该叫词法作用域,它指函数的定义部分所形成的作用域。
function fun1 () {
// 函数fun1的词法作用域
// 函数定义
// ....
}
运行上下文
函数在调用时会产生一个调用记录,其中包含函数在哪里被调用、传入函数的参数等信息。该记录也被称为运行上下文。一个函数的this总指向函数的运行上下文。当fun1在fun2中调用时,fun1的this指向fun2的定义上下文(词法作用域)。
function fun2 () {
// fun1的this指向该作用域
fun1();
// 函数定义
// ...
}
this的指向
this是运行上下文的一个属性,因此常说this指向函数的运行上下文。
this是在函数调用时被绑定的,与函数的声明位置(即词法作用域)没有任何关系。
call()和apply()
call()
call()方法的第一个参数为要指定的this对象,第二个参数及以后为函数运行所需的参数列表。
let obj = {
a: 1
}
function fun1 (num1, num2) {
console.log(this); // obj {a: 1}
console.log(num1 + num2); // 3
console.log(this.a); // 1
}
fun1.call(obj, 1, 2);
上述代码展示了call()的两种能力。一方面它改变了fun1调用时的this关键字,让其指向obj,并通过this关键字来访问obj中的属性。另一方面它将自己接受到的参数传入fun1。
apply()
call()和apply()本质上并无太大差别,唯一的区别在于call()接受的是参数列表,而apply()接受的是一个参数数组。
// ··· 同上
fun1.apply(obk, [1, 2]); // 效果和fun1.call(obj, 1, 2)相同
bind()
bind()创建一个新的函数, 当这个新函数被调用时this键值为其提供的值,其参数列表前几项值为创建时指定的参数序列。 ----- MDN
bind()的使用方法和call()十分类似,它的第一个参数是需要绑定的this对象,之后的参数为函数运行所需的参数列表。下面让我们来试验一下。
let obj = {
a: 1
}
function fun1 (num1, num2) {
console.log(this);
console.log(num1 + num2);
console.log(this.a);
}
fun1.bind(obj, 1, 2); // fun1 { ··· }
不同于apply()和call(),bind()返回的并不是fun1执行完毕的返回值,而是更改了this并初始化参数之后的fun1的函数定义。因此,要执行fun1,需在bind()后面再加一对括号:
fun1.bind(obj, 1, 2)(); // 改变this并传入参数后执行fun1
apply()、call()和bind()的比较
相同点
- 均可改变函数
this关键字的指向。
不同点
apply()接受一参数数组,返回函数执行的结果。call()接受一组参数,返回函数执行的结果。bind()接受一组参数,返回函数体。需在bind()后加小括号才能执行函数。
箭头函数的this绑定
ES6中新加入了箭头函数,它的绑定完全继承自调用它的作用域。绑定后无论使用apply()、call()还是bind()都不可修改。