🔥前端中 call,apply,bind 函数是干什么的,又是怎么实现的

403 阅读2分钟

call,apply,bind分析

作用:

call 、bind 、 apply 这三个函数都是更改this指针的指向,重新定义方法中的this指向哪个对象。

举例:

var name = '王某',age = 17;
var obj={
   name:'张某',
   age: '1岁',
   objAge:this.age,
   outputInfo:function (sex,hobby){
      console.log(this.name+' 年龄:'+this.age+' 性别:'+sex+' 爱好:'+hobby)
   }
}

console.log(obj.objAge);  // 17
obj.outputInfo();    //张某 年龄:1岁 性别:undefined 爱好:undefined
obj.outputInfo('男','玩游戏');    //张某 年龄:1岁 性别:男 爱好:玩游戏

在myFun函数外调用this.age 实际访问的是window对象 函数内的this指向obj。 如果新定义一个对象,但是想用一下 outputInfo 方法,就要用到call 、bind 、 apply

例如:

var obj={
   name:'张某',
   age: '1岁',
   objAge:this.age,
   outputInfo:function (sex,hobby){
      console.log(this.name+' 年龄:'+this.age+' 性别:'+sex+' 爱好:'+hobby)
   }
};
var newObj={
   name: '小李',
   age: '80岁'
};
obj.outputInfo.call(newObj,'男','穿裙子');  //小李 年龄:80岁 性别:男 爱好:穿裙子
obj.outputInfo.apply(newObj,['男','穿裙子']);  //小李 年龄:80岁 性别:男 爱好:穿裙子
obj.outputInfo.bind(newObj,'男','穿裙子')();   //小李 年龄:80岁 性别:男 爱好:玩游戏
obj.outputInfo.bind(newObj,['男','穿裙子'])();   //小李 年龄:80岁 性别:['男','穿裙子'] 爱好:undefined

此时outputInfo函数中的 this 就会指向传入的 newObj 对象。

区别和不同:

  1. call,apply,bind的传参方法不同。
  2. bind与call、apply的调用方法不同,bind在使用后要再手动调用一下,.bind()();
  3. call 传参: 参数依次列举
  4. apply 传参: 参数放在数组或者类数组中作为第二个参数传入
  5. bind 传参: 与call一样依次列举

自己实现call,apply,bind

call方法

Function.prototype.myCall = function(context,...args){
   //将当前被调用的方法定义在cxt.func上.(为了能以对象调用形式绑定this)
   let cxt = context || window;
   //新建一个唯一的Symbol变量避免重复
   let func = Symbol();
   cxt[func] = this;
   args = args ? args : [];
   //以对象调用形式调用func,此时this指向cxt 也就是传入的需要绑定的this指向
   const res = args.length > 0 ? cxt[func](...args) : cxt[func]();
   //删除该方法,不然会对传入对象造成污染(添加该方法)
   delete cxt[func];
   return res;
}

apply方法

Function.prototype.myApply = function(context,args = []){
   //将当前被调用的方法定义在cxt.func上.(为了能以对象调用形式绑定this)
   let cxt = context || window;
   //新建一个唯一的Symbol变量避免重复
   let func = Symbol();
   cxt[func] = this;
   const res = args.length > 0 ? cxt[func](...args) : cxt[func]();
   //删除该方法,不然会对传入对象造成污染(添加该方法)
   delete cxt[func];
   return res;
}

bind方法

Function.prototype.myBind = function(context,...args){
   //新建一个变量赋值为this,表示当前函数
   const fn = this;
   //判断有没有参数传进来,若为空则赋值[]
   args = args ? args : [];
   //返回一个newFn函数,在里面调用fn
   return function newFn(...newFnArgs){
       if(this instanceof newFn){
           return new fn(...args,...newFnArgs)
       }
       return fn.apply(context,[...args,...newFnArgs])
   };
}