call-apply-bind三者的作用,区别以及内部实现
1. call-apply-bind三者的作用
在JavaScript中,call-apply-bind是Function对象自带的三种方法,它们的作用都是用来改变函数内的this指向,传递的第一个参数都是this所要指向的对象,而且它们三个都可以传递参数(后续传值)。
2. call-apply-bind三者的区别
- call:调用一个对象的一个方法,用另一个对象替换当前对象,在传递参数的时候需要一个一个进行传递,而且定义完立即执行,返回值为调用方法的返回值,如果调用的方法没有返回值,则返回undefined
obj.call(obj1,arg1,arg2,arg3....);
- apply:和call很类似,都是立即执行,返回值为调用方法的返回值,如果调用方法没有返回值,则返回undefined,唯一不同的是,apply在传递参数的时候需要以数组的形式
obj.apply(obj1,[arg1,arg2,arg3.....]);
- bind:除了返回值是函数以外,它在传递参数的时候和call一样,都是一个一个传递,它在调用之后返回一个新的函数,不会立即执行
obj.bind(obj1,arg1,arg2,arg3...)();
3. call-apply-bind三者的内部实现
在内部实现的时候,需要把函数绑定在Function原型上,是原型上面的方法
- call
Function.prototype.myCall = function(context = window, ...args) {
if (this === Function.prototype) {
return undefined; //判断当前this是否为函数,用于防止Function.prototype.myCall()直接调用
}
context = context || window; //context为可选参数,如果不传的话,默认指向window
const fn = Symbol(); //利用symbol进行定义,可以保证不会重名
context[fn] = this; //将当前函数赋给这个属性,这样之后执行context[fn]的时候,fn里面的this指向就为context了
const result = context[fn](...args);
delete context[fn]; //调用完后立即删除symbol属性
return result;
}
//调用
let person1 = {
name:'王',
age:18,
say(...args){
console.log(`名字为${this.name},年龄为${this.age},参数为${args}`);
}
}
let person2 = {
name:'李',
age:20
}
person1.say.myCall(person2,1,2,3);
//输出 名字为李,年龄为20,参数为1,2,3
- apply
Function.prototype.myApply = function(context = window,args){
if(this === Function.prototype){
return undefined;
}
context = context || window;
const fn = Symbol();
context[fn] = this;
let result;
if(Array.isArray(args)){
result = context[fn](...args);
}else{
result = context[fn]();
}
delete context[fn];
return result;
}
//调用
let person1 = {
name:'王',
age:18,
say(...args){
console.log(`名字为${this.name},年龄为${this.age},参数为${args}`);
}
}
let person2 = {
name:'李',
age:20
}
person1.say.myApply(person2,[1,2,3]);
//输出 名字为李,年龄为20,参数为1,2,3
- bind
Function.prototype.myBind = function(obj,...args){
let self = this;
return function(){
let newArgs = args.concat(...arguments);
self.call(obj,newArgs);
}
}
//调用
let person1 = {
name:'王',
age:18,
say(...args){
console.log(`名字为${this.name},年龄为${this.age},参数为${args}`);
}
}
let person2 = {
name:'李',
age:20
}
person1.say.myBind(person2,1,2,3)(4,5);
//输出 名字为李,年龄为20,参数为1,2,3,4,5