自行实现call apply bind

Posted by Rimin on 2019-04-22

call, apply,bind三者都是用于改变对象绑定的this的值,但是在用法上有一些略微的差别。

call (Function.prototype.call()

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Product(name, price) {
this.name = name;
this.price = price;
}

function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}

console.log(new Food('cheese', 5).name);

//"cheese"

自行实现:

1
2
3
4
5
6
7
function callFn(obj, ...arg){
var _this = obj? obj || window;
_this.fn = this;
var res = _this.fn(...arg);
delet _this.fn;
return res;
}

apply (Function.prototype.apply())

call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
function Product(name, price) {
this.name = name;
this.price = price;
}

function Food(name, price) {
Product.apply(this, [name, price]);
this.category = 'food';
}

console.log(new Food('cheese', 5).name);

//"cheese"

自行实现:

1
2
3
4
5
6
7
function applyFn(object, array){
var _this = obj? obj || window;
_this.fn = this;
var res = _this.fn(...array);
delet _this.fn;
return res;
}

注意: call的性能比apply的性能好,可以尽可能的去用call

bind (Function.prototype.bind())

bind()方法创建一个新的函数,在bind()被调用时,这个新函数的thisbind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。

注意: bind函数返回的是一个原函数的拷贝, 并拥有指定的this值和初始参数。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Product(name, price) {
this.name = name;
this.price = price;
}

function Food(name, price) {
var fn = Product.bind(this, name, price);
console.log(res);
fn();
this.category = 'food';
}

console.log(new Food('cheese', 5).name);

//"cheese"

自行实现:(出自mdn)

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
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}

var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fBound
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};

// 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();

return fBound;
};
}