小明想要用数组的形式为 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
做者GitHub:https://github.com/pspgbhu
欢迎转载,但请注明出处,谢谢!