簡體   English   中英

如何構造JavaScript對象(使用'apply')?

[英]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而失敗。 我還不知道是否有更多的本機構造函數,這個函數無法處理。 我的問題是......

  • 是否有更新版本的JavaScript(ECMAScript 5)中的函數可以解決我的問題?
  • 如果沒有,是否有某種方法可以檢查有問題的構造函數,看看是否可以使用上述函數? (如果不能,我可能必須使用eval(“new”+ cname +“(”+ arglist +“)”)。)

/喬恩

在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調用時,將執行以下步驟:

  1. 設目標是F的[[TargetFunction]]內部屬性的值。
  2. 如果target沒有[[Construct]]內部方法,則拋出TypeError異常。
  3. 設boundArgs為F [[BoundArgs]]內部屬性的值。
  4. 讓args成為一個新列表,其中包含與列表boundArgs相同的值,順序相同,后面跟相同順序的列表ExtraArgs相同。
  5. 返回調用[[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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM