js深入学习之call,apply,bind函数的实现

996 阅读3分钟

1. call函数的实现

作用:函数调用,常用来给函数绑定指定的this,并执行该函数

参数:接收多个参数,第一个参数为要指定的 this对象

  • 如果没有传入指定的对象,或者指定的对象为 undefined,则默认指定 windows为要绑定的对象
var myObj = {
 name:'我是前端bug开发攻城狮'
}

function myFunc(name,age){
 console.log('argument.name===',name)
 console.log('this.name:age==',this.name,':',age)
}

Function.prototype.myCall = function(context){
 context = context || windows;
 context.fn = this;
 var args = [...arguments].splice(1,arguments.length-1);
 var result = context.fn(...args)
 delete context.fn;
 return result
}

myFunc.myCall(myObj,'路人甲',100)

第二版

var myObj = {
 name:'我是前端bug开发攻城狮'
}

var name = 'global'

function myFunc(name,age){
 console.log('argument.name==',name)
 console.log('this.name:age==',this.name,':',age)
}

Function.prototype.myCall = function(context){
 if(context && typeof context !== 'object'){
     return Error('第一个参数必须为对象')
 }
 context = context || window;
 context.fn = this;
 var args = [...arguments].splice(1,arguments.length-1);
 var result = context.fn(...args)
 delete context.fn;
 return result
}

// muFunc.myCall(myObj,'路人甲',100)
myFunc.myCall(123);

2. apply函数的实现

用法:同 call函数,唯一的区别就是,apply接收两个参数

  1. 要绑定的this对象
  2. 参数数组
var myObj = {
 name:'我是前端bug开发攻城狮'
}

var name = 'global name';

function myFunc(name,age){
 return {
     name: this.name,
     age:age,
     argName:name,
 }
}

Function.prototype.myBind = function(context,argArray){
 if(context && typeof context !== 'object'){
     return Error('第一个参数必须为对象')
 }
 context = context || window;
 context.fn = this;
 var result;
 if(argArray){
     result = context.fn(...argArray)
 }else{
     result = context.fn()
 }
 delete context.fn;
 return result
}

myFunc.myBind(myObj,['Kobe',24]);

3. bind函数的实现

用法:用来给调用的函数绑定一个this对象,并返回这个绑定了this之后的函数(只返回函数的引用,并不执行哦)

参数:接收多个参数,第一个参数为要绑定为this的对象,剩下的为函数的形参

注意:

  1. bind方法返回的函数,还可以继续收参数
  2. bind方法返回的函数,可以通过 new实例化
    • 通过 new 实例化之后,之前绑定的this会失效
function myFunction(name,age){
    console.log(this.value,name,age)
    return {
        value:this.value,
        name:name,
        age:age
    }
}


Function.prototype.myBind = function(context){

    if(context && typeof context !== 'object'){
        return Error('第一个参数必须为对象')
    }

    if(typeof this !== 'function'){
        return Error('只有函数才能调用myBind函数')
    }
    contex = context || window;
    var args = [...arguments].slice(1)
    var that = this;
   
    var fn = function(){
        that.call(this instanceof fn ? this : context,...args,...arguments)
    }
    return fn;
}

var fn1 = myFunction.myBind({value:'James'},'Kobe');
var result = new fn1('24')
console.log(result)

4. 总结

相同点:call,apply,bind函数都是用来为函数绑定指定的 this对象的,且三个函数的第一个参数都必须为要绑定的this对象,没传则默认为 window,传的不是对象则报错

不同点:

  • call:call函数从第二个参数开始,接收的参数都作为函数的形参,可以有多个
  • apply:apply与call唯一的区别就是,apply接收的第二个参数是一个数组,所有函数的形参都包含在数组里面
  • bind:bind函数不同于前两个函数,bind函数返回一个绑定 this 之后的函数的引用。而不是直接调用。且调用返回的函数的时候,可以继续传参,作为函数的形参使用(后续传入的参数会对应函数的形参列表,依次对应)。最特别的一点是,bind函数返回的函数的引用,可以通过 new 实例化,实例化之后的函数就失去了bind绑定的this。