阅读 481

javascript bind polyfill

昨天看到一个面试题将的自己实现一个bind函数,自己思考了一下决定写写试试.

1 首先明确第一个功能实现this的显示绑定

bind函数最明显的功能就是实现this的显示绑定, bind返回的是一个新函数:
复制代码
Function.prototype.bind = function() {
   var slice = Array.prototype.slice,
       context = arguments[0],
       _this = this,
       outerArg = slice.call(arguments, 1);
       return function() {
           _this.apply(context, outerArg)
       }
}
复制代码
这种写法实现了最基础的this显示绑定,然而bind还是一种函数的柯里化,能够先传参,下面对代码稍加进行更改.
复制代码

2 实现柯里化

Function.prototype.bind = function() {
    var slice = Array.prototype.slice,
        context = arguments[0],
        _this = this,
        outerArg = slice.call(arguments, 1);
        return function() {
            var innerArg = slice.call(argunments); // 新增
            var arg = outerArg.contact(innerArg); // 新增
            _this.apply(context, arg)
        }
 }
复制代码
这样就实现了柯里化和this的显示绑定, 但是这并没有结束. 大多数情况下我们现在写的bind都能满足我们的使用,但是官方文档上有这么一句话
    A bound function may also be constructed using the new operator: doing
    so acts as though the target function had instead been constructed.
    The provided this value is ignored, while prepended arguments are
    provided to the emulated function.
    
这句话叙述的是关于函数被bind后如果我们对他进行new 操作后的行为;
复制代码

3 this 的问题

我们来看这个截图,testBind是我们上面所写的bind的实现方式, 当我们对fn进行testBind绑定后传入context(这里是obj), 
调retFn进行 new操作后 他返回的是一个空对象, 再看看 我们用原生的bind去绑定fn传入obj 对retBindFn进行new操作后会返回一个对象包含a属性.
这个差异说明了我们目前实现的testBind函数还是有功能欠缺的, 那欠缺的在哪里呢?

this! 没错就是this. 原生的bind虽然把使用bind显示绑定将函数内部this指向我们传入的context
但是new操作是将函数内部的this指向他new操作后反返回的实例, 两个操作都是改变this指向,那么谁更优先级更高一些呢?
复制代码

传入的obj中的a属性没变!!!  new操作更厉害,优先级更高一些.
那说明在这两种情况同时存在的情况下函数内部的this要指向函数本身的this(因为new操作会将此this指向new操作返回的实例);
那这个操作应该如何实现呢, 这里可以借助一个中间函数;
复制代码
   Function.prototype.bind = function() {
       var slice = Array.prototype.slice,
           context = arguments[0],
           _this = this,
           outerArg = slice.call(arguments, 1);
       var retFn = function() {
           var innerArg = slice.call(argunments); 
           var arg = outerArg.contact(innerArg); 
           var oThis = this instanceof F ? this : context
           _this.apply(oThis, arg)
       }
       var F = function() {}
       F.prototype = this.prototype;
       retFn.prototype = new F()
       return retFn
   }
复制代码
借助F函数根据我的理解是让我们区分这里是是否使用了new 
F.prototype = this.prototype;
retFn.prototype = new F()
如果没有这两句, 我们所有的new retFn(), 内部的this指向的是实例本身即为 Object 的实例。
不使用new 操作 retFn 内部this指向的是context(不传的话一般采用默认的this绑定,this指向的是window)也是 Object 的实例。

retFn.prototype = new F()
我们没法判断是否使用new操作, 而借助F函数 如果使用new RetFn()的话 首先内部this 就是F的实例也是Object的实例。
这样的话我们就能能够通过这种方法判断是否使用new 操作从而选择this的指向.
F.prototype = this.prototype; 是在纠正retFn的原型, 作者才疏学浅, 如有错误请多指教,请多包涵复制代码