在JavaScript中绑定/应用构造函数

Mar*_*eed 10 javascript constructor variadic-functions

我正在寻找使用任意数量的参数调用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])
Run Code Online (Sandbox Code Playgroud)

第一个有所需的结果:

print(new f()) //=> Sat Jan 01 2000 00:00:00 GMT-0500 (EST)
Run Code Online (Sandbox Code Playgroud)

但其他两个不:

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)
Run Code Online (Sandbox Code Playgroud)

所以有些东西在某处乱了.关于什么的想法?难道仅仅是一个坏主意,东西混合像apply,bind和/或callnew

Sem*_*lon 27

以前接受的答案是不正确的.你可以使用bind,call和apply with constructors来创建新的构造函数 - 测试中唯一的问题就是你忘记了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)
Run Code Online (Sandbox Code Playgroud)

这三个都是instanceof日期.

调用的参数是执行上下文后跟要应用的参数.Apply的参数是执行上下文和参数数组.绑定的参数是执行上下文后跟绑定的参数.

这样的论点适用,例如,是要为其上下文应用 绑定后跟一个阵列,其是参数(日期)结合(因此第一阵列构件是绑定的上下文参数).这就是调用或应用绑定令人困惑的原因; 向两者提供上下文参数感觉很奇怪.

请注意,在将bind与构造函数一起使用时,始终忽略context参数,因为"new"显式创建了新的上下文.当context参数与保持清楚无关时,我使用null,但它可以是任何东西.

同时,在这些示例中应用和调用确实需要知道它们要应用/调用bind的上下文是Date函数.我尽可能地将'Date'切换为'Function',以帮助阐明实际提供上下文的内容.当我们在Date.bind上调用apply或call时,我们实际上正在调用apply或调用未附加到Date对象的bind方法.在这种情况下,绑定方法可以来自任何功能.它可能是Number.bind.call(Date,null,2000,0,1),结果将完全相同.

如果不明显为什么,请考虑以下示例之间的区别:

context.method();
Run Code Online (Sandbox Code Playgroud)

var noLongerAMethod = context.method;
noLongerAMethod();
Run Code Online (Sandbox Code Playgroud)

在第二种情况下,该方法已经脱离其原始上下文(...除非之前已绑定),并且如果它在内部依赖于"this",则表现不同.当我们将任何给定函数作为属性绑定时,而不是直接执行它,它只是指向Function.prototype上的泛型绑定方法的另一个指针.

我个人认为我不需要调用或应用绑定,很难想象它会是一个很好的解决方案的情况,但是我发现创建新构造函数的绑定构造函数在某些时候非常有用. .无论如何,这是一个有趣的谜题.


ota*_*tay 5

bindapply/ 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;
}
Run Code Online (Sandbox Code Playgroud)

实际上,这将为您的构造函数创建一个子类

然后你的代码:

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);
Run Code Online (Sandbox Code Playgroud)

您也可以将此函数编写为本机函数Function.prototype或作为本机bind函数的扩展。