call 、apply 以及 bind 的区别和用法 以及手写实现
手写实现 call、apply、bind
call 方法作用
调用一个对象的一个方法,以另一个对象替换当前对象。也就是说改变方法中 this 指向,第一个参数代表 this 指向的对象,后面紧跟的参数为函数原有的形参
const A = {
name: '我是A对象的name',
getName: function () {
console.log(this.name);
},
};
const B = {
name: '我是B对象的name',
};
A.getName(); // //结果 我是A对象的name
A.getName.call(B); //结果 我是B对象的name
- 使用 call 改变了 A 对象中 getName 方法的 this 指向,使其指向了 B 对象
- fn.call(obj)可以看成 obj.fn(...args),这样 fn 中的 this 就指向了 obj
- 我们可以使用 call 方法,借助其他对象中存在的方法实现自己的功能,例如 es5 将伪数组转为真正的数组,new 关键字的实现也借助了 call 方法等
自定义 call 方法
const A = {
name: '我是A对象的name',
getName: function (a, b, c) {
console.log(this.name, a + b + c);
},
};
const B = {
name: '我是B对象的name',
};
//call前面是fucntion函数,所以该方法需要添加到Function构造函数的原型对象上
Function.prototype.myCall = function (context, ...args) {
if (typeof this !== 'function') {
throw new Error(`${this} is not function`);
}
if (!context instanceof Object) {
throw new Error(`${context} is not Object`);
}
//将函数绑定到对象上作为对象上的方法
context.fn = this;
//执行对象中的方法
const result = context.fn(...args);
//删除被绑定的方法
delete context['fn'];
return result;
};
A.getName.myCall(B, 1, 2, 3); //我是B对象的name 6
A.getName.call(B, 1, 2, 3); //我是B对象的name 6
apply 与 call 对比
功能相同,都是改变 this 指向
语法不同 apply 的语法:函数名.call(obj,[参数 1,参数 2,参数 3...])
apply 方法的使用
const A = {
name: '我是A对象的name',
getName: function (a, b, c) {
console.log(this.name, a + b + c);
},
};
const B = {
name: '我是B对象的name',
};
A.getName.apply(B, [1, 2, 3]); //输出 我是B对象的name 6
自定义 apply 方法
const A = {
name: '我是A对象的name',
getName: function (a, b, c) {
console.log(this.name, a + b + c);
},
};
const B = {
name: '我是B对象的name',
};
Function.prototype.myApply = function (context, args) {
if (typeof this !== 'function') {
throw new Error(`${this}is not function`);
}
if (!context instanceof Object) {
throw new Error(`${context} is not Object`);
}
if (args && !Array.isArray(args)) {
throw new Error(`${args} is not Array`);
}
context.fn = this;
const result = context.fn(...args);
return result;
};
A.getName.myApply(B, [1, 2, 3]); //输出 我是B对象的name 6
bind 与 apply 和 call 对比
- 功能相同,都是改变 this 指向
- 返回值不同,bind 会返回一个函数,我们需要调用这个返回值
- 入参与 call 相同
bind 方法的使用
const A = {
name: '我是A对象的name',
getName: function (a, b, c) {
console.log(this.name, a + b + c);
},
};
const B = {
name: '我是B对象的name',
};
A.getName.bind(B)(
1,
2,
3
) //输出 我是B对象的name 6
``;
自定义 bind 方法
const A = {
name: '我是A对象的name',
getName: function (a, b, c) {
console.log(this.name, a + b + c);
},
};
const B = {
name: '我是B对象的name',
};
Function.prototype.myBind = function (context) {
const self = this;
if (typeof self !== 'function') {
throw new Error(`${self}is not function`);
}
if (!context instanceof Object) {
throw new Error(`${context} is not Object`);
}
//bin方法返回一个函数
return function (...args) {
context.fn = self;
const result = context.fn(...args);
delete context.fn;
return result;
};
};
A.getName.myBind(B)(1, 2, 3); //输出 我是B对象的name 6