3

我有一个参数列表,例如var args = ['blah', 1, 3.9],我想将其应用于需要更新的内容,例如new bleh.Thinggy(a, b, c).

我想做以下var m = {}; bleh.Thinggy.apply(m, args);

我担心有些事情我没有想到有谁知道这是否安全?

4

2 回答 2

3

您当前的方法有缺陷,因为原型继承不会按预期工作。for 构造函数
的等价物是:method.apply(context, args)

// Given a list of arguments `args`:
var bindArgs = [Constructor.prototype].concat(args);
new (Function.prototype.bind.apply(Constructor, bindArgs));

Function.prototype.bind和的作用Function.prototype.apply在相应的文档中进行了说明。记住:.bind返回一个函数!

为了简单起见,我将解释如何使用.bind固定数量的参数,比如两个。然后,以下具有相同的效果:

Math.max.apply(Math, 2, 3);
Math.max.bind(Math, 2, 3)();

Math.max.apply(Math, 2, 3, 4, 5);
Math.max.bind(Math, 2, 3)(4, 5);

如果您甚至浏览过文档,您肯定会理解第一种形式。第二种形式虽然更棘手。它在这种情况下有效,因为参数的位置Math.max不相关。考虑所有参数的最大值,其中所有参数都被同等对待。

现在,下面是一个带有自定义函数的示例:

function echoMe(name, age) {
    console.log('Hello ' + name + '. Your age is ' + age);
    console.log('this is ', this);
}
echoMe('Rob', '19');
// "Hello Rob. Your age is 19"
// "this is [object DOMWindow]"  (non-strict mode)
var echoYou = echoMe.bind(null, "Oops");
echoYou("Peter", "19");
// "Hello Oops. Your age is Peter"
// "this is null"

因为在这种情况下参数的位置很重要,所以最后一个例子显示了一些奇怪的东西。事实上,第一个参数被该方法绑定到“Oops”.bind。传递给绑定函数 echoYou的参数被附加到参数列表中。此外,您注意到上下文this已更改为null.

有趣..让我们尝试使用以下方法更改上下文.apply

function printThisFood() {
    console.log("this.food is " + this.food);
}
printThisFood.apply({food: "Fish"});
// "this.food is fish"
var locked = printThisFood.bind({food: "Strong"});
locked.apply({food: "Weak"});
// "This.food is Strong"

如您所见,this.food仍然指向通过.bind!定义的上下文中的方法。


因此,我们知道如何锁定函数的上下文,以及将任意数量的固定参数传递给函数。这可以应用于构造函数,从而产生我在答案之上提出的函数。要验证它是否按预期工作:

function Constructor() {
    console.log(this instanceof Constructor); // true
    console.log(this, arguments);             // Convince yourself via console
}
var bindArgs = [Constructor.prototype].concat([1, 2]);
// is equal to [Constructor.prototype, 1, 2]

var BoundConstructor = Function.prototype.bind.apply(Constructor, bindArgs);
var instance = new BoundConstructor();

// Eliminated intermediate variable, and put on one line
var instance = new (Function.prototype.bind.apply(Constructor, bindArgs));

注意:我省略()了单行中的括号,因为没有这些就可以初始化构造函数。new Image并且new Image()行为相同。
要立即从构造的方法中读取属性(或调用方法),您可以将整个表达式括在括号中或附加()以消除歧义:

(new (Function.prototype.bind.apply(Constructor, bindArgs))).method()
new (Function.prototype.bind.apply(Constructor, bindArgs))().method();

注 2:它仍然认为附加参数附加到参数列表中。此属性还可用于“预设”给定构造函数的第一个参数:

function Stupid(obvious1, obvious2, foo) { this.interesting = foo; }
Stupid.prototype.onlymethod = function() { return this.interesting};
var saveKeyStroke = Function.prototype.bind.call(Stupid, Stupid.prototype, 1, 2);
// Or, equivalent:
//var saveKeyStroke=Function.prototype.bind.apply(Stupid,[Stupid.prototype,1,2]);

new saveKeyStroke('Fourth argument').onlymethod(); // "Fourth argument"
new saveKeyStroke().onlymethod(); // undefined
(new saveKeyStroke).onlymethod(); // undefined
于 2012-10-10T19:50:38.650 回答
0

Apply 是安全的,但它不会返回任何bleh.Thinggy. 如果你想要实例,bleh.Thinggy那么你必须在使用 bleh.Thinggy.apply 之前创建它。

代码:

var m = new bleh.Thinggy; // m is instance of  bleh.Thinggy.
        bleh.Thinggy.apply(m, args);
        ... use m as instance of bleh.Thinggy.apply
于 2012-10-10T19:49:35.850 回答