手写bind函数
实现bind函数
参考MDN提供的Polyfill方案
Function.prototype.myBind = function(context){ //这里对调用者做一个判断,如果不是函数类型,直接抛异常 if(typeof this !== 'function'){ throw '调用必须为函数' } //当我们调用bind函数时,我们可能传了不只一个参数 //如 fun.bind({}, arg1, arg2) //我们需要把后面的参数拿出来 let args = Array.prototype.slice.call(arguments, 1); let fToBind = this; let fNOP = function(){}; let fBound = function(){ return fToBind.apply(this instanceof fNOP ? this : context, args.concat(arguments)); } if(this.prototype){ fNOP.prototype = this.prototype; } fBound.prototype = new fNOP(); return fBound; }
fBound函数这里有个判断 this instanceof FNOP 这个其实是为了避免一种情况,因为bind函数返回的是一个函数,当我们把这个函数实例化(就是new fun())
根据官方文档 当返回的函数被实例化的时候,this指向会锁定指向该实例,不管我们传入的参数指定this指向。
在下面我们 返回的fBound函数时 继承一个空函数 FNOP, 当返回的函数被实例化之后,this instanceof fNOP 结果为true,从而指定this指向
function a (){} function b (){} a.prototype = new b(); //如果我们返回的函数实例化了 let c = new a(); c instanceof b //true //但是大多数情况我们都是 a instanceof b // false
如果这里明白了,那后面的就简单了,context 参数就是我们手动指定的this指向, 当我们绑定bind时会传递多个参数,执行的时候也会带参数,我们就需要把bind
函数除掉第一个以外的参数和我们调用方式时的参数进行拼接
function foo (){} //示例中 args 就是指的[arg1, arg2] //args.concat(arguments) 就是将所有的arg1,arg2...arg4的参数进行拼接 let newFoo = foo.bind({}, arg1, arg2); newFoo(arg3, arg4);
另外 arguments 参数不要搞混淆了,上面那个获取的是bind时的参数(就是{}, arg1, arg2)
下面的arguments 参数是指的调用时的 (就是 arg3, arg4)