你不懂JS书 - 软装订

时间:2014-08-23 13:17:48

标签: javascript

我正在阅读You don't know JS。在其中,有一节讨论soft binding技术。基本上它是将函数绑定到特定范围/上下文的变体。

从书中可以看出:

  

如果有一种方法可以为默认绑定提供不同的默认值(不是全局或未定义),那么这仍然很好,同时仍然可以通过隐式绑定或显式绑定技术手动绑定该函数。

if (!Function.prototype.softBind) {
    Function.prototype.softBind = function(obj) {
        var fn = this,
            curried = [].slice.call( arguments, 1 ),
            bound = function bound() {
                return fn.apply(
                    (!this ||
                        (typeof window !== "undefined" &&
                            this === window) ||
                        (typeof global !== "undefined" &&
                            this === global)
                    ) ? obj : this,
                    curried.concat.apply( curried, arguments )
                );
            };
        bound.prototype = Object.create( fn.prototype );
        return bound;
    };
}

一般来说,我理解除了这部分之外该功能的作用:

bound.prototype = Object.create( fn.prototype );

为什么在使用这种“软绑定”技术时我们必须设置原型?

2 个答案:

答案 0 :(得分:2)

  

为什么我们必须在使用这个"软绑定时设置原型"技术

完整性比其他任何事情更重要。如果有人试图创建软绑定函数的new实例,他们希望生成的对象[[Prototype]]链接到与原始函数相同的对象{{1指出。因此,我们确保将.prototype设置为等于引用相同的对象。

有人想要在软约束函数上调用bound.prototype的可能性很低,我想,但为了更安全,它仍然包括在内。同样,顺便说一句,对于内置new的polyfill也是如此:

https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind#Polyfill

答案 1 :(得分:0)

来自that页面:

  

为什么new能够覆盖硬绑定有用?

     

此行为的主要原因是创建一个函数(可以   用于构造对象的新东西,基本上忽略了   这个硬绑定但预设部分或全部功能   参数。 bind(..)的一个功能是任何参数   在第一个此绑定参数默认为标准后传递   底层函数的参数(技术上称为“部分函数”)   应用程序“,这是”currying“的一个子集。)

我猜想softbind具有相同的好处(提供一个传递给它的默认参数的构造函数)你必须设置原型,或者当你使用绑定函数作为构造函数时你缺少原型函数:

//softBind code removed

function Test(arg1,arg2){
    this.arg1=arg1;
    this.arg2=arg2;
}
Test.prototype.sayArgs=function(){
  console.log('args:',this.arg1,this.arg2);
}
//the binding part doesn't do anything so can pass null
var BoundTest = Test.softBind(null, 'arg1');
var bt = new BoundTest('arg2');
bt.sayArgs();//=args:arg1 arg2

如果您打算以这种方式使用它,虽然您不必将softBind添加到Function.prototype,您可以使用普通绑定,本机绑定或MDN polyfill。

请注意,使用polyfill时,您无法将falsy参数作为第一个要绑定的参数传递,否则它将会中断。

//Using the MDN bind polyfill you can't pass any falsy
// value like null, undefined,"",0 and false
var BoundTest = Test.bind({}, 'arg1');
var bt = new BoundTest('arg2');
bt.sayArgs();//=args:arg1 arg2;

在文章中,给出的例子实际上是破碎的:

var bar = foo.bind( null, "p1" );
var baz = new bar( "p2" );

应该是:

var bar = foo.bind('anything non falsy' , "p1" );

<强> [更新]

//removed if, so it'll set softbind every time
    Function.prototype.softBind = function(obj) {
        var fn = this,
            curried = [].slice.call( arguments, 1 ),
            bound = function bound() {
                return fn.apply(
                    (!this ||
                        (typeof window !== "undefined" &&
                            this === window) ||
                        (typeof global !== "undefined" &&
                            this === global)
                    ) ? obj : this,
                    curried.concat.apply( curried, arguments )
                );
            };
        bound.prototype = Object.create( fn.prototype );
        return bound;
    };

function Test(){
  //this has the right prototype and has
  // the default arguments
  console.log('this is:', this,'arguments',arguments);
  this.name='test';
}
Test.prototype.something=22

var BoundTest = Test.softBind(null,'arg1','arg2');

var bt = new BoundTest();
//bt is same as new Test('arg1','arg2') would be
console.log('bt is:',bt);
//this.name did not affect window
console.log(window.name);//not test 
console.log(bt instanceof Test);//true