背景:
小明想要用数组的形式为 Cls.func
传入多个参数,他想到了以下的写法:
var a = new Cls.func.apply(null, [1, 2, 3]);
然而浏览器却报错 Cls.func.apply is not a constructor。
乍一看是 new 操作符去修饰 Cls.func.apply 了,于是他又这么写:
var a = (new Cls.func).apply(null, [1, 2, 3]);
浏览器依旧报错。。。好吧,还是好好查一查相关的解决方法吧,还好这是个好时代,没有什么是网上查不出来的。
思路:
在网上找到了非常关键的几个解决方案和思路。
参考链接 http://*.com/questions/1606797/use-of-apply-with-new-operator-is-this-possible
关键摘抄:
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() 这种写法:
var a = new (Function.prototype.bind.call(Fn, null, 1, 2, 3));
call() 接受多个参数,第一个参数为函数执行的上下文环境,后面的参数会依次传递给前面的 bind 作为参数。
所以 bind() 接到的参数为 bind(null, 1, 2, 3)。所以上面的那种写法就等同于:
var a = new ( Fn.bind(null, 1, 2, 3)() );
同理再推导 Function.prototype.bind.apply() 写法:
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
作者GitHub:https://github.com/pspgbhu
欢迎转载,但请注明出处,谢谢!