0%

bind & apply & call

时常会搞混 bindapplycall 这三者的用法以及来意,现在就一次性讲清楚吧

apply

apply() 方法调用一个具有给定 this 的函数,以及一个数组(或类数组对象)的形式提供的参数。

1
2
3
4
5
const nums = [1, 2, 3, 4];
const max = Math.max.apply(null, nums);
console.log(max); // 4
const min = Math.min.apply(null, nums);
console.log(min); // 1

call

call() 方法与 apply() 方法类似。该方法调用一个具有给定 this 的函数,从第二个参数之后全都是参数。

1
2
3
4
5
6
7
8
9
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price); // 让 Product 中 this 指向 Food
this.category = "food";
}
console.log(new Food("cheese", 5).name);

bind

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

1
2
3
4
5
6
7
8
9
10
11
12
const module = {
x: 42,
getX: function () {
return this.x;
},
};

console.log(module.getX()); // 42
const unboundGetX = module.getX;
console.log(unboundGetX()); // undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX()); // 42

基础的 bind() 实现:

在不考虑 new 绑定的情况下,这样写是足够了的。

1
2
3
4
5
6
Function.prototype.myBind = function (obj), ...args) {
const self = this;
return function (...newArgs) {
return self.apply(obj), args.concat(newArgs));
};
};

考虑 new 之后就要在原型上面去做一部分修改

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
// 目标函数
function fun(...args) {
console.log(this);
console.log(args);
}
// 目标函数原型对象上的一个方法cher
func.prototype.cher = function () {
console.log(1);
}

// bind传入参,一个是要改变this指向的对象,后面的是要传入的实参数值
Function.prototype.myBind = function (obj,...args) {

var _that = this;
// bing会返回一个新的函数
var newBind = function(...list) {
// 如果作为了构造函数,this指向构造函数,否则就指向传入的对象
var targetObj = this instanceof newBind ? this : obj; 
// 使用apple方法把this指向改变
that.apply(targetObj ,[...list,...args]);
}
// 在用bind改变this指向的时候,返回的函数不会立即执行。
// 如果用返回的函数作为构造函数实例化一个对象的时候,这个对象的原型对象还是目标对象的原型对象,所以要纠正过来
newBind.prototype = Object.create(_that.prototype);
newBind.prototype.constructor = _that;

//返回这个函数
return newBind;
}

var fn2 = fun.myBind({a:1},4,3);
var newFn2 = new fn2(12); //newBind{} 1,2,4,3
console.log(newFn2); //newBind{}
console.log(newFn2.cher()); //1