我一直在寻找使用任意数量的参数调用Javascript构造函数的解决方案,并找到了一些好的SO帖子,这让我相信这三个调用应该是一样的。但是,至少在rhino和node.js中,它们不会:
1. f = Date.bind(Date, 2000,0,1)
2. g = Date.bind.call(Date, 2000, 0, 1)
3. h = Date.bind.apply(Date, [2000, 0, 1])
第一个有所需的结果:
print(new f()) //=> Sat Jan 01 2000 00:00:00 GMT-0500 (EST)
但其他两个则没有:
print(new g()) //=> Thu Feb 01 1900 00:00:00 GMT-0500 (EST)
print(new h()) //=> Wed Jun 01 1904 00:00:00 GMT-0400 (EST)
所以有些东西在某处乱了。关于什么的想法?将apply
,bind
和/或call
与new
等内容混合在一起是不是一个坏主意?
答案 0 :(得分:27)
previously accepted answer不正确。您可以使用bind,call和apply with constructor来创建新的构造函数 - 测试中唯一的问题是您已经忘记bind.apply和bind.call正在应用并调用 bind ,而不是构造函数本身,所以你给出了错误的参数。
f = Date.bind(null, 2000,0,1)
g = Function.bind.call(Date, null, 2000, 0, 1)
h = Function.bind.apply(Date, [ null, 2000, 0, 1 ])
new f() //=> Sat Jan 01 2000 00:00:00 GMT-0500 (EST)
new g() //=> Sat Jan 01 2000 00:00:00 GMT-0500 (EST)
new h() //=> Sat Jan 01 2000 00:00:00 GMT-0500 (EST)
这三个人都是instanceof
日期。
调用的参数是执行上下文后跟应用的参数。 Apply的参数是执行上下文和参数数组。 绑定的参数是执行上下文,后跟绑定的参数。
因此,要应用的参数是应用 bind (Date)的上下文,后跟一个数组,该数组是的参数< / em> bind(所以第一个数组成员是bind的上下文参数)。这就是调用或应用绑定令人困惑的原因;向两者提供上下文参数感觉很奇怪。
请注意,在使用带有构造函数的bind时,始终会忽略context参数,因为&#39; new&#39;显式创建一个新的上下文。当context参数与保持清楚无关时,我使用null,但它可以是任何东西。
同时,在这些示例中应用和调用确实需要知道它们要应用/调用bind的上下文是Date函数。我改变了日期&#39;到&#39;功能&#39;在可能的情况下,帮助阐明实际提供背景的地方。当我们在Date.bind上调用apply或call时,我们实际上正在调用apply或调用未附加到Date对象的bind方法。在这种情况下,绑定方法可以来自任何功能。它可能是Number.bind.call(Date,null,2000,0,1),结果将完全相同。
如果不明白为什么,请考虑以下示例之间的区别:
context.method();
和
var noLongerAMethod = context.method;
noLongerAMethod();
在第二种情况下,该方法已脱离其原始上下文(...除非之前已被绑定),并且如果它依赖于&#39;这种情况将表现不同。内部。当我们将任何给定函数作为属性绑定时,而不是直接执行它,它只是指向Function.prototype上泛型绑定方法的另一个指针。
我个人认为我不需要打电话或申请绑定,很难想象它会成为一个好的解决方案的情况,但绑定构造函数来创建新的构造函数是我偶尔发现非常有用的东西。无论如何,它是一个有趣的谜题。
答案 1 :(得分:4)
bind
和apply
/ call
仅适用于功能而非构造函数,因此基本上使用原生方法不能这样做,一种方法是编写bindConstruct
方法,但它可能涉及额外的复杂性:
function bindConstruct(fn) {
// since constructor always accepts a static this value
// so bindConstruct cannot specify this
var extraArgs = [].slice.call(arguments, 1);
// create a 'subclass' of fn
function sub() {
var args = extraArgs.concat([].slice.call(arguments));
fn.apply(this, args);
}
sub.prototype = fn.prototype;
sub.prototype.constructor = sub;
return sub;
}
实际上,这会为您的构造函数创建一个子类。
然后你的代码:
var MyClass = function(x, y) {
console.log(arguments);
console.log(x + y);
}
var BindedMyClass = bindConstruct(MyClass, 1, 2, 3);
var c = new BindedMyClass(4, 5);
console.log(c instanceof MyClass);
console.log(c instanceof BindedMyClass);
您也可以将此功能写入Function.prototype
或作为原生bind
功能的扩展名。