我有一个参数列表,例如var args = ['blah', 1, 3.9]
,我想将其应用于需要更新的内容,例如new bleh.Thinggy(a, b, c)
.
我想做以下var m = {}; bleh.Thinggy.apply(m, args);
我担心有些事情我没有想到有谁知道这是否安全?
我有一个参数列表,例如var args = ['blah', 1, 3.9]
,我想将其应用于需要更新的内容,例如new bleh.Thinggy(a, b, c)
.
我想做以下var m = {}; bleh.Thinggy.apply(m, args);
我担心有些事情我没有想到有谁知道这是否安全?
您当前的方法有缺陷,因为原型继承不会按预期工作。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
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