# 手写 call、apply、bind
# call
Function.prototype.Call = function (context, ...args) {
// 当 context 为 undefined 或 null 时,context 指向window
if (!context || context === null) {
context = window
}
// 使用 Symbol 创建唯一的 key 值,防止与原有属性冲突
let fn = Symbol()
// 将当前函数挂载到 context 对象下,this 指向调用 call 的函数
context[fn] = this
// 隐式绑定 this,如执行 obj.foo(), foo 内的 this 指向 obj
const res = context[fn](...args)
// 执行完毕后,删除新增的属性
delete context[fn]
return res
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# apply
// apply与call相似,只有第二个参数是一个数组,
Function.prototype.Apply = function (context, args) {
if (!context || context === null) {
context = window
}
let fn = Symbol()
context[fn] = this
const res = context[fn](...args)
delete context[fn]
return res
}
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# bind
Function.prototype.Bind = function (context, ...args) {
if (!context || context === null) {
context = window
}
let fn = this
let f = Symbol()
const result = function (...args1) {
if (this instanceof fn) {
// result 如果作为构造函数被调用, ths 指向的是 new 出来的对象
// this instanceof fn,判断 new 出来的对象是否为 fn 的实例
this[f] = fn
let res = this[f](...args, ...args1)
delete this[f]
return res
} else {
// bind 返回的函数作为普通函数被调用时
context[f] = fn
let res = context[f](...args, ...args1)
delete context[f]
return res
}
}
// 如果绑定的是构造函数 那么需要继承构造函数原型属性和方法
// 实现继承的方式: 使用 Object.create
result.prototype = Object.create(fn.prototype)
return result
}
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
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
← 展开层叠数组的六种方法 函数式编程 →