一文带你重写call、apply、bind

2,278 阅读2分钟

“Keep Learning!期待更好的自己”——大家好!我是Marine😄

小编荐语:本文旨在帮助大家彻底掌握call、apply、bind

重写Call

在重写之前我们分析一下call到底是怎么执行的

function func(a,b){
	console.log(this,a,b)
}
let obj ={
	name:'Marine'
}
func.call(obj,10,20)

1.func首先基于_proto_找到Function.prototype.call,并且让call方法执行

2.在call方法执行的过程中(call方法中的this->func),把func执行,并且让func中的this变为传递的第一个参数obj,再并且把10/20当作实惨传递给func,最后接收func执行的返回值,把返回值作为call方法的返回值返回

// 模拟内置基于c++完成的CALL方法
Function.prototype.myCall = function myCall(context,...params){
   //context->最后要改变的函数中的this指向obj
   //params->最后要传递给函数的实参信息[10,20]
   //this->要处理的函数 fn
   context = context==null?window:context;
   //必须保证context是个对象,因为他将作为函数的this
   let contextType = typeof context;
   if(!/^(object|function)$/i.test(contextType)){
       //context.constructor:当前所属的类
       //context = new context.constructor(context);//=>不适合Symbol/BigInt,Symbol/BigInt不能被new
       context = Object(context)
   }
   let key = Symbol('KEY')
   //把函数当成对象的某个成员,(成员名唯一:防止修改原始对象的结构值)
   context[key] = this;
   //基于“对象[成员]()”方法把函数执行,此时函数中的THIS就是对象(把参数传递给函数,并且接收返回值)
   let result = context[key](...params);
   //设置的成员用完后删除掉
   delete context[key];
   //把函数的返回值作为CALL方法执行的结果返回
   return result;
}

重写Apply

  • 和call的区别只是传递的参数是数组
Function.prototype.myApply = function myApply(context,params){
    context = context==null?window:context;
    //必须保证context是个对象,因为他将作为函数的this
    let contextType = typeof context;
    if(!/^(object|function)$/i.test(contextType)){
        //context.constructor:当前所属的类
        //context = new context.constructor(context);//=>不适合Symbol/BigInt
        context = Object(context)
    }
    let key = Symbol('KEY')
    //把函数当成对象的某个成员,(成员名唯一:防止修改原始对象的结构值)
    context[key] = this;
    //基于“对象[成员]()”方法把函数执行,此时函数中的THIS就是对象(把参数传递给函数,并且接收返回值)
    let result = context[key](...params);
    //设置的成员用完后删除掉
    delete context[key];
    //把函数的返回值作为CALL方法执行的结果返回
    return result;
}

重写bind

  • call/apply:立即执行函数并且修改里面的THIS
  • bind:利用柯理化函数的编程思想,预先把“需要执行的函数/改变的THIS/传递的实参”等信息存储在闭包中,后期达到条件(事件出发/定时器等),先执行返回的匿名函数,在执行匿名函数的过程中,再去改变THIS等 =>THIS和参数的预处理
Function.prototype.myBind = function myBind(context,...params){
	//this->处理的函数func
    //context->要改变的函数中的this执行 obj
    //params ->最后给函数传递的实参
	let _this = this;
	return function(...agrs){
        //args->可能传递的事件等信息
    	_this.call(context,...params.concat(agrs))
    }
}

写在最后

本人前端菜鸡一枚,如有错误,请大佬多多指教共同进步