Fn.bind.apply() 解決 new 操做符不能用與 apply 或 call 同時使用

背景:

小明想要用數組的形式爲 Cls.func 傳入多個參數,他想到了如下的寫法:html

var a = new Cls.func.apply(null, [1, 2, 3]);

然而瀏覽器卻報錯 Cls.func.apply is not a constructor。
乍一看是 new 操做符去修飾 Cls.func.apply 了,因而他又這麼寫:git

var a = (new Cls.func).apply(null, [1, 2, 3]);

瀏覽器依舊報錯。。。好吧,仍是好好查一查相關的解決方法吧,還好這是個好時代,沒有什麼是網上查不出來的。github


思路:

在網上找到了很是關鍵的幾個解決方案和思路。數組

參考連接 http://stackoverflow.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible瀏覽器

關鍵摘抄:app

function newCall(Fn) {
    return new (Function.prototype.bind.apply(Fn, arguments));
    // or even
    // return new (Fn.bind.apply(Fn, arguments));
    // if you know that Fn.bind has not been overwritten
}

// It can be used as follows:
var s = newCall(Fn, a, b, c);

// or even directly:
var a = new (Function.prototype.bind.call(Fn, null, 1, 2, 3));

var a = new (Function.prototype.bind.apply(Fn, [null, 1, 2, 3]));

以上關鍵就在於 .bind.apply() 或 .bind.call() 這中寫法。
Function.prototype.bind() 等同於 Fn.bind() 會建立一個新的函數,第一個參數爲新函數的 this 指向,然後多個參數爲綁定函數被調用時,這些參數將置於實參以前傳遞給被綁定的方法。函數

先分析一下 Function.prototype.bind.call() 這種寫法:this

var a = new (Function.prototype.bind.call(Fn, null, 1, 2, 3));

call() 接受多個參數,第一個參數爲函數執行的上下文環境,後面的參數會依次傳遞給前面的 bind 做爲參數。
因此 bind() 接到的參數爲 bind(null, 1, 2, 3)。因此上面的那種寫法就等同於:prototype

var a = new ( Fn.bind(null, 1, 2, 3)() );

同理再推導 Function.prototype.bind.apply() 寫法:code

var a = new (Function.prototype.bind.apply(Fn, [null, 1, 2, 3]);

call() 接受兩個參數,第一個參數爲函數執行的上下文環境,第二個參數爲數組,數組的每一項會一次做爲 bind() 的參數,所以 bind() 接受到的參數也爲 bind(null, 1, 2, 3)。所以也等價於:

var a = new ( Fn.bind(null, 1, 2, 3)() );

解決:

有了上面的推導,小明這時候就能夠輕易的寫出本身想要的結果了,同時爲了拓展方便,小明決定寫一個通用的方法:

function newApply(Fn, argsAry) {
    argsAry.unshift(null);
    return new (Fn.bind.apply(Fn, argsAry));
}

// 調用
newApply(Cls.func, [1, 2, 3]) // well done !!

做者博客:pspgbhu http://www.cnblogs.com/pspgbhu/

原文連接:http://www.cnblogs.com/pspgbhu/p/6796795.html

做者GitHubhttps://github.com/pspgbhu

歡迎轉載,但請註明出處,謝謝!

相關文章
相關標籤/搜索