在原生js中关于bind实现的一些疑惑


这里是原生js中bind的实现,我一些地方不是很理解,


 if(!Function.prototype.bind){
    Function.prototype.bind=function(obj){
        var slice=[].slice,
        args=slice.call.(arguments,1),
        self=this,
        nop=function(){},
        bound=function(){
        return self.apply(this, instanceof nop ? this:{obj||{}}),
            args.concat(slice.call(arguments)))
        };
        nop.prototype=self.prototype;
        bound.prototype=new nop();
        return bound;

    };
}

关于它的上下文是怎么变化的,我能够理解
但是我不太清楚,第一:


 nop.prototype=self.prototype;
        bound.prototype=new nop();

这里是在做什么?
第二是,这里的参数,关于参数数组的做法。

JavaScript

Deliy 9 years, 6 months ago

首先你这个 Polyfill 应该自己加了料进去了,那个 this, instance of nop 应该是多了一个 , ,具体可参考 MDN 的 Polyfill 写法: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Glob...

先回答一下问题二:明白 bind 的用法就必须要知道 apply 的用法, MDN 指出, apply 是直接修改了函数内部的指向到第一个参数,并将第二个参数数组传参进函数并运行这个函数。也就是说


 var obj = {test: function() { console.log(this, arguments) }},
    func = obj.test;

obj.test("Hello", ",", "world", "!");
func.apply(obj, ["Hello", ",", "world", "!"]);

这两种运行方式是一样的。那么回到 Polyfill 中发现参数的写法是 args.concat(slice.call(arguments)) args 是将 bind 时候定义的除第一个参数外的其它参数,而此时的 arguments 是指函数调用时候的参数,通过数组的操作将这两个参数合并成一个数组传入函数内部。看个例子你可能更容易明白:


 /** 代码接上 **/
var newFunc = func.bind(obj, "Hello", ",");
newFunc("world", "!");

那么再来回答问题一,这个是典型的属性继承的方法,本来使用


 bound.prototype = self.prototype

就可以将原属性集成过来了,但是这样两个对象属性都指向同一个地方,修改 bound.prototype 将会造成 self.prototype 也发生改变,这样并不是我们的本意。所以通过一个空函数 nop 做中转,能有效的防止这种情况的发生。

二岩大明神 answered 9 years, 6 months ago

Your Answer