我有一个参数列表,例如var args = ['blah', 1, 3.9]
,我想将它应用于需要像new bleh.Thinggy(a, b, c)
这样的新事物。
我想执行以下var m = {}; bleh.Thinggy.apply(m, args);
我担心有些东西我没想到有人知道这是否安全吗?
答案 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.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"
因为在这种情况下参数的位置很重要,所以最后一个例子显示了一些奇怪的东西。实际上,.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 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
答案 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