摘要
- 三种方法均可改变函数
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
键值为其提供的值,其参数列表前几项值为创建时指定的参数序列。 -----
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()
都不可修改。