# 手写 apply/call/bind
JavaScript 中 call()、apply()、bind() 的用法——菜鸟教程 (opens new window)
这是 Function 的原型方法, 每一个函数实例都拥有这些方法。方法的作用是重新定义现有函数的执行环境,即函数执行过程中的 this
指向,以实现函数复用。
三个方法的第一个参数都是重新指定的函数调用对象。如果未指定,非严格模式下指向 window
。
call
方法和 apply
方法都是立即执行,区别在于传参形式的不同:
call
方法传入参数列表apply
方法传入参数数组
bind
方法返回一个重新定义了执行环境的函数,其传参方式与 call
方法相同。
bind 方法使用到了闭包,把定义时传入的 this 对象存在外包函数里,然后返回一个使用了该 this 对象的匿名函数。
在调用一个存在的函数时,你可以为其指定一个 this
对象。 this
指当前对象,也就是正在调用这个函数的对象。 使用 apply
, 你可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。
Function.prototype.myCall = function (context, ...args) {
/*
手写思路就是给待绑定的环境添加一个独一无二的属性,指向当前的函数实例;
然后在该环境下调用函数实例,则函数内部的 this 指向就变成了该环境
注意使用完毕后要将其删除,以免造成内存泄漏
*/
if (typeof context === 'undefined' || context === null) {
context = window
}
const fnSymbol = Symbol()
// 这里的 this 是这个函数实例对象
context[fnSymbol] = this
const res = context[fnSymbol](...args)
delete context[fnSymbol]
return res
}
/*
myApply 与 myCall 写法基本相同,唯一不同在传参差异
*/
Function.prototype.myApply = function (context, args) {
if (typeof context === 'undefined' || context === null) {
context = window
}
const fnSymbol = Symbol()
context[fnSymbol] = this
const res = context[fnSymbol](...args)
delete context[fnSymbol]
return res
}
/*
bind 函数不直接执行,而是返回一个可执行的函数
(这里取个巧,直接调用前面写好的 apply / call 函数)
*/
Function.prototype.myBind = function(context, ...args) {
return () => {
return this.apply(context, args)
}
}
1
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
28
29
30
31
32
33
34
35
36
37
38
39
40
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
28
29
30
31
32
33
34
35
36
37
38
39
40