手写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)

posted @ 2019-08-08 08:16  wangziye  阅读(1938)  评论(0编辑  收藏  举报