JS原生函数实现之call/apply/bind

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
let foo = {
a: 10
}

function bar(name, age) {
console.log(name, age);
console.log(this.a);
}


/*
let foo = {
a: 10,
bar: function(name,age) {
console.log(name, age);
console.log(this.a);
}
}
foo.bar();//10
*/


Function.prototype.call2 = function (context) {
let _context = context || window;
_context.fn = this;
let arg = [];
for (let i = 1; i < arguments.length; i++) {
arg.push(arguments[i])
}
let res = _context.fn(...arg);
delete _context.fn;
return res;
}

Function.prototype.apply2 = function (context) {
let _context = context || window;
_context.fn = this;
if (Array.isArray(arguments[1])) {
let res = _context.fn(...arguments[1]);
delete _context.fn;
return res;
} else if (arguments[1]) {
throw new Error('need array');
} else {
let res = _context.fn();
delete _context.fn;
return res;
}
}

Function.prototype.bind2 = function (context) {
let self = this; //self === bar
let arg = Array.prototype.slice.call(arguments, 1);
let fbound = function () {
let bindArg = Array.prototype.slice.call(arguments);
//当作为构造函数时,this 指向实例,self 指向绑定函数(bar),
//因为下面一句 `fbound.prototype = this.prototype;`,已经修改了 fbound.prototype 为 绑定函数(bar)的 prototype,
//此时结果为 true,当结果为 true 的时候,this 指向实例。

//当作为普通函数时,this 指向 window,self 指向绑定函数,此时结果为 false,当结果为 false 的时候,this 指向绑定的 context。
// console.log(this instanceof self);
// console.log(this);
// console.log(self);
self.call2(this instanceof self ? this : context, ...arg.concat(bindArg));
}
fbound.prototype = this.prototype;
return fbound;
}

// bar.call2(foo, 'kenvin', 18);
// bar.apply2(foo, ['jack', 1888]);

let b = bar.bind2(foo, 'kkk')
b(15);

参考文章

JavaScript深入之call和apply的模拟实现