[英]How to construct JavaScript object (using 'apply')?
我正在尋找一種基於(a)構造函數的名稱構造任意JavaScript對象的方法,以及(b)包含參數的數組。 我在stackoverflow上的另一個線程中發現了這個函數(由Matthew Crumley撰寫?):
function construct(constructor, args) {
function F() { return constructor.apply(this, args); }
F.prototype = constructor.prototype;
return new F();
}
這適用於用JavaScript編寫的構造函數,但如果我嘗試構造(Date,[...])則它會因TypeError而失敗。 我還不知道是否有更多的本機構造函數,這個函數無法處理。 我的問題是......
/喬恩
在ES5中,您可以通過bind
。
function construct(constructor, args) {
return new (constructor.bind.apply(constructor, [null].concat(args)));
}
這是有效的,因為bind
仍然使用[[Construct]]抽象運算符當綁定函數出現在new
的右側時每http://es5.github.com/#x15.3.4.5.2
15.3.4.5.2 [[Construct]]
當使用
bind
函數創建的函數對象的[[Construct]]內部方法,使用參數列表ExtraArgs調用時,將執行以下步驟:
- 設目標是F的[[TargetFunction]]內部屬性的值。
- 如果target沒有[[Construct]]內部方法,則拋出TypeError異常。
- 設boundArgs為F [[BoundArgs]]內部屬性的值。
- 讓args成為一個新列表,其中包含與列表boundArgs相同的值,順序相同,后面跟相同順序的列表ExtraArgs相同。
- 返回調用[[Construct]]目標的內部方法的結果,提供args作為參數。
但是大多數嘗試將語言功能反向移植到ES3實現上的Function.prototype.bind
實現都沒有正確處理用作構造函數的綁定函數,所以如果你不確定你的代碼是在真正的ES5實現上運行那么你必須回到hackery的三角形:
function applyCtor(ctor, args) {
// Triangle of hackery which handles host object constructors and intrinsics.
// Warning: The goggles! They do nothing!
switch (args.length) {
case 0: return new ctor;
case 1: return new ctor(args[0]);
case 2: return new ctor(args[0], args[1]);
case 3: return new ctor(args[0], args[1], args[2]);
case 4: return new ctor(args[0], args[1], args[2], args[3]);
case 5: return new ctor(args[0], args[1], args[2], args[3], args[4]);
case 6: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
case 7: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
case 8: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
case 9: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
case 10: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
case 11: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]);
case 12: return new ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
}
// End triangle of hackery
// Create a throwaway subclass of ctor whose constructor does nothing.
function TemporarySubclass() {}
TemporarySubclass.prototype = ctor.prototype;
var instance = new TemporarySubclass();
instance.constructor = ctor; // Patch constructor property
// Run the constructor. This assumes that [[Call]] internal method is the same as
// [[Construct]]. It might work with some builtins/host objects where "new` would not.
var returnValue = ctor.apply(instance, args);
// If the constructor returned a non-primitive value, return it instead.
switch (typeof returnValue) {
case 'object':
// If ctor is Array, it reaches here so we don't use broken Array subclass.
// Ditto for Date.
if (returnValue) { return returnValue; }
break;
case 'function':
return returnValue;
}
// Return the constructed instance.
return instance;
}
我最終可能會得到Mike的三角形簡化版:
function applyCtor2(ctor, args) {
switch (args.length) {
case 0: return new ctor();
case 1: return new ctor(args[0]);
case 2: return new ctor(args[0], args[1]);
// add more cases if you like
}
var jsStr = "new ctor(args[0]";
for (var i=1; i<ar.length; i++) jsStr += ",args[" + i + "]";
jsStr += ")";
return eval(jsStr);
}
我不是在這里使用'申請',但我不會錯過它。 ;-) 任何意見?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.