手写apply、call、bind函数

实现apply、call函数

查看
实现apply
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Function.prototype.zApply = function (thisArg, args = []) {
thisArg = typeof thisArg === 'object' ? thisArg : Object(thisArg)

Object.defineProperty(thisArg, 'fn', {
configurable: true,
enumerable: false,
value: this
})

const result = thisArg.fn(...args)
delete thisArg.fn
return result
}

function foo(arg1, arg2) {
console.log(this)
console.log(arg1, arg2)
}

const bar = { name: 1 }
foo.zApply(bar, ['1', '2'])
实现call
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Function.prototype.zCall = function (thisArg, ...args) {
thisArg = typeof thisArg === 'object' ? thisArg : Object(thisArg)

Object.defineProperty(thisArg, 'fn', {
configurable: true,
enumerable: false,
value: this
})

const result = thisArg.fn(...args)
delete thisArg.fn
return result
}

function foo(arg1, arg2) {
console.log(this)
console.log(arg1, arg2)
}

const bar = { name: 1 }
foo.zCall(bar, '1', '2')

以上代码存在相同之处,可以尝试对以上操作进行封装。

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
Function.prototype.execute = function (thisArg, ...args) {
thisArg = typeof thisArg === 'object' ? thisArg : Object(thisArg)

Object.defineProperty(thisArg, 'fn', {
configurable: true,
enumerable: false,
value: this
})

const result = thisArg.fn(...args)
delete thisArg.fn
return result
}


Function.prototype.zCall = function (thisArg, ...args) {
this.execute(thisArg, ...args)
}

Function.prototype.zApply = function (thisArg, args = []) {
this.execute(thisArg, ...args)
}

function foo(arg1, arg2) {
console.log(this)
console.log(arg1, arg2)
}

const bar = { name: 1 }
const bar1 = { name1: 2 }
foo.zApply(bar, ['1', '2'])
foo.zCall(bar1, '1', '2')

手写实现的弊端:

  • 以上是通过隐式绑定this机制实现的,但需要向调用者传入参数,这样会对外部产生影响,且容易覆盖原有对象的属性,虽然最后会将添加的属性删除,但对于thisArg所引用的对象来说,影响可能是很大的。

实现bind函数

查看
实现bind
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function.prototype.zBind = function (thisArg, ...args) {

thisArg = typeof thisArg === 'object' ? thisArg : Object(thisArg)

Object.defineProperty(thisArg, 'fn', {
enumerable: false,
value: this
})
return function (...args1) {
return thisArg.this(...args, ...args1)
}
}

foo.bind({ name: 1 }, '1', '2')('3', '4')

弊端:

  • 和手写实现apply/call的思路基本相同,但为调用着添加了个属性,且不能对其删除,影响很大。