在newing时使用变量参数

时间:2012-10-10 19:43:18

标签: javascript new-operator apply

我有一个参数列表,例如var args = ['blah', 1, 3.9],我想将它应用于需要像new bleh.Thinggy(a, b, c)这样的新事物。

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

我担心有些东西我没想到有人知道这是否安全吗?

2 个答案:

答案 0 :(得分:3)

您当前的方法存在缺陷,因为原型继承无法按预期工作 构造函数的等效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.bindFunction.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"

因为在这种情况下参数的位置很重要,所以最后一个例子显示了一些奇怪的东西。实际上,.bind方法的第一个参数是绑定到“Oops”。传递给绑定函数 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定义的上下文中的方法!


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

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 Imagenew 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

答案 1 :(得分:0)

应用是安全的,但它不会返回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