call() 、 apply() 、bind()方法的实现

327 阅读2分钟

1、作用:

   call/apply/bind的核心理念:借用方法。
   借助已实现的方法,改变方法中数据的this指向,减少重复代码,节省内存。

2、区别:

   call()、apply()的第一个参数相同,就是指定的对象,这个对象就是该函数的执行上下文;
   不同的在于两者之间的参数:
   call()在第一个参数后,后续所有参数就是传入该函数的值;
   apply()只有两个参数,第一个是对象,第二个是数组,这个数组就是该函数的参数;
   bind()方法的不同在于:它会返回执行上下文被改变的函数而不会立即执行,前两者
   会直接执行函数。他的参数和call()相同。
    fun.call(thisArg, param1, param2, ...)
    fun.apply(thisArg, [param1,param2,...])
    fun.bind(thisArg, param1, param2, ...)

3、使用场景

call,apply的效果完全一样,它们的区别也在于

  • 参数数量/顺序确定就用call,参数数量/顺序不确定的话就用apply
  • 考虑可读性:参数数量不多就用call,参数数量比较多的话,把参数整合成数组,使用apply。
  • 参数集合已经是一个数组的情况,用apply

4、手撕函数

call()

——将函数设为对象的属性

——执行并删除这个函数

——指定this到函数并传入给定参数执行函数

——如果不传入参数,默认指向window

   Function.prototype.mycall = function(ctx){
       ctx= ctx ? Object(ctx) : window;
       ctx.fn = this;
       let args = [...arguments].slice(1);
       let result = ctx.fn(...args);
       delete ctx.fn;
       return result;
   }

apply()

Function.prototype.myapply = function(ctx,arr){
    ctx = ctx ? Object(ctx) : window;
    ctx.fn = this;
    let result;
    if(!arr){
        result = ctx.fn();
    }else{
        result = ctx.fn(...arr);
    }
    delete ctx.fn;
    return result;
}

bind()

Function.prototype.mybind = function(ctx,...args){
    const fn = this;
    if(typeof this !== 'function'){
        throw new TypeError('bind must be a function')
    }
    args = args ? args: [];
    // bind会返回一个函数,不会执行,考虑new的情况
    return function newFn(...newFnArgs){
        if(this instanceof newFn){
            return new fn(...args,...newFnArgs)
        }
        return fn.apply(ctx,[...args,...newFnArgs])
    }
}