วิธีตั้งค่าต้นแบบของวัตถุ JavaScript ที่ได้รับการสร้างอินสแตนซ์แล้ว?


106

สมมติว่าฉันมีวัตถุfooในรหัส JavaScript ของฉัน fooเป็นวัตถุที่ซับซ้อนและสร้างขึ้นที่อื่น ฉันจะเปลี่ยนต้นแบบของfooวัตถุได้อย่างไร?

แรงจูงใจของฉันคือการตั้งค่าต้นแบบที่เหมาะสมให้กับออบเจ็กต์ที่ต่อเนื่องกันจาก. NET เป็นตัวอักษร JavaScript

สมมติว่าฉันเขียนโค้ด JavaScript ต่อไปนี้ในหน้า ASP.NET

var foo = <%=MyData %>;

สมมติว่าMyDataเป็นผลมาจากการเรียกใช้. NET JavaScriptSerializerบนDictionary<string,string>วัตถุ

ในขณะทำงานสิ่งนี้จะกลายเป็นสิ่งต่อไปนี้:

var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}];

อย่างที่คุณเห็นfooกลายเป็นอาร์เรย์ของวัตถุ ฉันต้องการเริ่มต้นfooด้วยต้นแบบที่เหมาะสม ฉันไม่ได้ต้องการที่จะปรับเปลี่ยนหรือObject.prototype Array.prototypeฉันจะทำเช่นนี้ได้อย่างไร?


คุณต้องการเพิ่มในต้นแบบที่มีอยู่หรือเปลี่ยนเป็นต้นแบบใหม่?
SLaks

คุณหมายถึงทำการเปลี่ยนแปลงต้นแบบหรือเปลี่ยนต้นแบบจริง ๆ ในขณะที่เปลี่ยนต้นแบบหนึ่งออกมาแล้วแทนที่ด้วยอีกต้นแบบ ฉันไม่แน่ใจด้วยซ้ำว่าจะเป็นไปได้ในภายหลัง
James Gaunt

2
คุณหมายถึงคุณสมบัติต้นแบบที่ชัดเจนหรือลิงก์ต้นแบบโดยนัย ? (สองสิ่งนี้เป็นสองสิ่งที่แตกต่างกันมาก)
Šime Vidas

ตอนแรกฉันกังวลกับเรื่องนี้stackoverflow.com/questions/7013545/…
Vivian River

1
คุณคุ้นเคยกับ Backbone extendหรือ Google goog.inheritหรือไม่? นักพัฒนาหลายแห่งที่มีวิธีการที่จะสร้างมรดกก่อนที่จะเรียกผู้สูงอายุnewคอนสตรัคซึ่งเป็นก่อนที่เราจะได้รับและไม่ต้องกังวลกับการเอาชนะObject.create Object.prototype
Ryan

คำตอบ:


114

แก้ไขกุมภาพันธ์ 2555: คำตอบด้านล่างไม่ถูกต้องอีกต่อไป กำลังเพิ่ม __proto__ ใน ECMAScript 6 เป็น "ทางเลือกเชิงบรรทัดฐาน" ซึ่งหมายความว่าไม่จำเป็นต้องนำไปใช้ แต่ถ้าเป็นเช่นนั้นจะต้องเป็นไปตามชุดของกฎที่กำหนด ขณะนี้ยังไม่ได้รับการแก้ไข แต่อย่างน้อยก็จะเป็นส่วนหนึ่งของข้อกำหนดของ JavaScript อย่างเป็นทางการ

คำถามนี้ซับซ้อนกว่าที่คิดบนพื้นผิวมากและนอกเหนือจากระดับการจ่ายเงินของคนส่วนใหญ่ในเรื่องความรู้เกี่ยวกับ Javascript ภายใน

prototypeคุณสมบัติของวัตถุจะใช้เมื่อมีการสร้างวัตถุลูกใหม่ของวัตถุที่ การเปลี่ยนมันไม่ได้สะท้อนให้เห็นในตัววัตถุ แต่จะสะท้อนให้เห็นเมื่อวัตถุนั้นถูกใช้เป็นตัวสร้างสำหรับวัตถุอื่นและไม่มีประโยชน์ในการเปลี่ยนต้นแบบของวัตถุที่มีอยู่

function myFactory(){};
myFactory.prototype = someOtherObject;

var newChild = new myFactory;
newChild.__proto__ === myFactory.prototype === someOtherObject; //true

วัตถุมีคุณสมบัติ [[ต้นแบบ]] ภายในซึ่งชี้ไปยังต้นแบบปัจจุบัน วิธีการทำงานคือเมื่อใดก็ตามที่คุณสมบัติบนอ็อบเจ็กต์ถูกเรียกมันจะเริ่มต้นที่อ็อบเจ็กต์จากนั้นขึ้นไปตามโซ่ [[ต้นแบบ]] จนกว่าจะพบว่าตรงกันหรือล้มเหลวหลังจากรูทอ็อบเจ็กต์ต้นแบบ นี่คือวิธีที่ Javascript อนุญาตให้สร้างรันไทม์และแก้ไขอ็อบเจ็กต์ มีแผนที่จะค้นหาสิ่งที่ต้องการ

__proto__คุณสมบัติที่มีอยู่ในการใช้งานบางคน (มากตอนนี้): การดำเนินการใด ๆ ของ Mozilla ทุกคน WebKit ฉันรู้ว่าของบางคนอื่น ๆ คุณสมบัตินี้ชี้ไปที่คุณสมบัติ [[ต้นแบบ]] ภายในและอนุญาตให้แก้ไขหลังการสร้างบนวัตถุ คุณสมบัติและฟังก์ชั่นใด ๆ จะเปลี่ยนให้ตรงกับต้นแบบทันทีเนื่องจากการค้นหาที่ถูกล่ามโซ่นี้

คุณลักษณะนี้ในขณะที่ได้รับการปรับให้เป็นมาตรฐานในขณะนี้ยังคงไม่ใช่ส่วนที่จำเป็นของ JavaScript และในภาษาที่รองรับคุณลักษณะนี้มีโอกาสสูงที่จะทำให้โค้ดของคุณตกอยู่ในหมวดหมู่ "ไม่ได้เพิ่มประสิทธิภาพ" เอ็นจิ้น JS ต้องพยายามอย่างดีที่สุดในการจัดประเภทโค้ดโดยเฉพาะโค้ด "ร้อน" ซึ่งมีการเข้าถึงบ่อยมากและหากคุณกำลังทำอะไรแปลก ๆ เช่นการปรับเปลี่ยน__proto__พวกเขาจะไม่เพิ่มประสิทธิภาพโค้ดของคุณเลย

โพสต์นี้https://bugzilla.mozilla.org/show_bug.cgi?id=607863โดยเฉพาะกล่าวถึงการนำไปใช้ในปัจจุบัน__proto__และความแตกต่างระหว่างกัน การใช้งานทุกครั้งไม่เหมือนกันเพราะเป็นปัญหาที่ยากและไม่ได้รับการแก้ไข ทุกอย่างใน Javascript ไม่แน่นอนยกเว้น.) ไวยากรณ์ข.) วัตถุโฮสต์ (DOM ที่มีอยู่นอก Javascript ทางเทคนิค) __proto__และค.) ส่วนที่เหลืออยู่ในมือของคุณและนักพัฒนารายอื่น ๆ ทั้งหมดดังนั้นคุณจะเห็นได้ว่าทำไมจึง__proto__ยื่นออกมาเหมือนนิ้วโป้งที่เจ็บ

มีสิ่งหนึ่งที่__proto__อนุญาตให้ทำสิ่งนั้นไม่ได้นั่นคือการกำหนดต้นแบบวัตถุที่รันไทม์แยกจากตัวสร้าง นี่เป็นกรณีการใช้งานที่สำคัญและเป็นหนึ่งในสาเหตุหลักที่__proto__ยังไม่ตาย มีความสำคัญมากพอที่จะเป็นประเด็นสนทนาอย่างจริงจังในการกำหนด Harmony หรือเร็ว ๆ นี้เรียกว่า ECMAScript 6 ความสามารถในการระบุต้นแบบของวัตถุในระหว่างการสร้างจะเป็นส่วนหนึ่งของ Javascript เวอร์ชันถัดไปและจะเป็น ระฆังที่ระบุ__proto__วันเป็นตัวเลขอย่างเป็นทางการ

ในระยะสั้นคุณสามารถใช้ได้__proto__หากคุณกำหนดเป้าหมายเบราว์เซอร์ที่รองรับ (ไม่ใช่ IE และไม่เคยมี IE) มีแนวโน้มว่ามันจะใช้งานได้ใน webkit และ moz ในอีก 10 ปีข้างหน้าเนื่องจาก ES6 จะไม่ได้รับการสรุปจนถึงปี 2013

Brendan Eich - re: แนวทางของ Object method ใหม่ใน ES5 :

ขออภัย ... แต่สามารถตั้งค่าได้__proto__นอกเหนือจากกรณีการใช้งานวัตถุเริ่มต้น (เช่นบนวัตถุใหม่ที่ยังไม่สามารถเข้าถึงได้ซึ่งคล้ายกับ Object.create ของ ES5) เป็นความคิดที่แย่มาก ฉันเขียนสิ่งนี้โดยออกแบบและใช้งานได้__proto__เมื่อ 12 ปีที่แล้ว

... การขาดการแบ่งชั้นเป็นปัญหา (พิจารณาข้อมูล JSON ด้วยคีย์"__proto__") และที่แย่กว่านั้นความสามารถในการเปลี่ยนรูปหมายถึงการนำไปใช้งานต้องตรวจสอบห่วงโซ่ต้นแบบแบบวัฏจักรเพื่อหลีกเลี่ยงการหลุดลอก [ต้องมีการตรวจสอบอย่างต่อเนื่องสำหรับการเรียกซ้ำแบบไม่มีที่สิ้นสุด]

ในที่สุดการกลายพันธุ์__proto__บนวัตถุที่มีอยู่อาจทำลายวิธีการที่ไม่ใช่ทั่วไปในวัตถุต้นแบบใหม่ซึ่งอาจไม่สามารถทำงานบนวัตถุตัวรับ (โดยตรง) ที่__proto__กำลังตั้งค่าได้ นี่เป็นเพียงการปฏิบัติที่ไม่ดีรูปแบบหนึ่งของความสับสนโดยเจตนาโดยทั่วไป


พังเลิศ! แม้ว่าจะไม่ใช่สิ่งเดียวกับต้นแบบที่เปลี่ยนแปลงได้ แต่ ECMA Harmony อาจจะใช้พร็อกซีซึ่งช่วยให้คุณสามารถใช้ฟังก์ชันเพิ่มเติมบนวัตถุบางอย่างโดยใช้รูปแบบ catchall
Nick Husher

2
ปัญหาของ Brendan Eich มีถิ่นกำเนิดในภาษาต้นแบบโดยรวม การทำ __proto__ non-writable, configurableอาจเป็นการแก้ไขข้อกังวลเหล่านี้โดยบังคับให้ผู้ใช้กำหนดค่าคุณสมบัติใหม่อย่างชัดเจน ในท้ายที่สุดการปฏิบัติที่ไม่ดีเกี่ยวข้องกับการใช้ความสามารถของภาษาในทางที่ผิดไม่ใช่ความสามารถในตัวเอง __proto__ ที่เขียนได้นั้นไม่ใช่สิ่งที่ไม่เคยได้ยินมาก่อน มีคุณสมบัติที่เขียนไม่ได้อื่น ๆ อีกมากมายและในขณะที่มีอันตรายก็มีแนวทางปฏิบัติที่ดีที่สุดเช่นกัน ไม่ควรเอาหัวค้อนออกเพียงเพราะสามารถใช้เพื่อทำร้ายคนอื่นได้อย่างไม่เหมาะสม
หมุน

__proto__จำเป็นต้องมีการกลายพันธุ์เนื่องจาก Object.create จะสร้างเฉพาะ Objects ไม่ใช่ฟังก์ชันเช่นหรือ Symbols, Regexes, DOM elements หรือ host object อื่น ๆ หากคุณต้องการให้วัตถุของคุณสามารถเรียกได้หรือมีความพิเศษในรูปแบบอื่น ๆ แต่ยังคงเปลี่ยนห่วงโซ่ต้นแบบคุณจะติดอยู่โดยไม่สามารถตั้งค่า__proto__หรือพร็อกซีได้
user2451227

2
มันจะดีกว่าถ้ามันไม่ได้ทำด้วยคุณสมบัติวิเศษ แต่ใช้ Object.setPrototype แทนซึ่งจะช่วยขจัดปัญหา " __proto__ใน JSON" ความกังวลอื่น ๆ ของ Brendan Eich นั้นน่าหัวเราะ โซ่ต้นแบบซ้ำหรือใช้ต้นแบบด้วยวิธีการที่ไม่เพียงพอสำหรับวัตถุที่ได้รับข้อผิดพลาดโปรแกรมเมอร์ไม่ผิดพลาดภาษาและไม่ควรจะเป็นปัจจัยและนอกจากพวกเขาจะเกิดขึ้นกับ Object.create __proto__ก็เช่นกันเช่นเดียวกับที่กำหนดได้อย่างอิสระ
user2451227

1
IE 10 __proto__สนับสนุน
kzh


14

คุณสามารถใช้constructorกับอินสแตนซ์ของวัตถุเพื่อเปลี่ยนต้นแบบของวัตถุในตำแหน่ง ฉันเชื่อว่านี่คือสิ่งที่คุณขอให้ทำ

ซึ่งหมายความว่าหากคุณมีfooซึ่งเป็นตัวอย่างของFoo:

function Foo() {}

var foo = new Foo();

คุณสามารถเพิ่มคุณสมบัติbarให้กับอินสแตนซ์ทั้งหมดได้Fooโดยทำดังต่อไปนี้:

foo.constructor.prototype.bar = "bar";

นี่เป็นซอแสดงหลักฐานของแนวคิด: http://jsfiddle.net/C2cpw/ ไม่แน่ใจว่าเบราว์เซอร์รุ่นเก่าจะใช้วิธีนี้ได้ดีเพียงใด แต่ฉันค่อนข้างมั่นใจว่ามันจะทำงานได้ดี

หากคุณตั้งใจที่จะผสมฟังก์ชันลงในออบเจ็กต์ข้อมูลโค้ดนี้ควรทำงาน:

function mix() {
  var mixins = arguments,
      i = 0, len = mixins.length;

  return {
    into: function (target) {
      var mixin, key;

      if (target == null) {
        throw new TypeError("Cannot mix into null or undefined values.");
      }

      for (; i < len; i += 1) {
        mixin = mixins[i];
        for (key in mixin) {
          target[key] = mixin[key];
        }

        // Take care of IE clobbering `toString` and `valueOf`
        if (mixin && mixin.toString !== Object.prototype.toString) {
          target.toString = mixin.toString;
        } else if (mixin && mixin.valueOf !== Object.prototype.valueOf) {
          target.valueOf = mixin.valueOf;
        }
      }
      return target;
    }
  };
};

1
+1: นี่เป็นข้อมูลและน่าสนใจ แต่ไม่ได้ช่วยให้ฉันได้รับสิ่งที่ต้องการจริงๆ ฉันกำลังอัปเดตคำถามให้เจาะจงมากขึ้น
Vivian River

คุณยังสามารถใช้foo.__proto__.bar = 'bar';
Jam Risser

9

คุณสามารถทำได้foo.__proto__ = FooClass.prototypeAFAIK ที่ Firefox, Chrome และ Safari รองรับ โปรดทราบว่า__proto__สถานที่ให้บริการไม่ได้มาตรฐานและอาจหายไปในบางจุด

เอกสารอ้างอิง: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/proto โปรดดูที่http://www.mail-archive.com/jsmentors@googlegroups.com/msg00392.htmlสำหรับคำอธิบายว่าเหตุใดจึงไม่มีObject.setPrototypeOf()และเหตุใดจึง__proto__เลิกใช้งาน


3

คุณสามารถกำหนดฟังก์ชันตัวสร้างพร็อกซีของคุณจากนั้นสร้างอินสแตนซ์ใหม่และคัดลอกคุณสมบัติทั้งหมดจากออบเจ็กต์ดั้งเดิมไปยังมัน

// your original object
var obj = { 'foo': true };

// your constructor - "the new prototype"
function Custom(obj) {
    for ( prop in obj ) {
        if ( obj.hasOwnProperty(prop) ) {
            this[prop] = obj[prop];
        }
    }
}

// the properties of the new prototype
Custom.prototype.bar = true;

// pass your original object into the constructor
var obj2 = new Custom(obj);

// the constructor instance contains all properties from the original 
// object and also all properties inherited by the new prototype
obj2.foo; // true
obj2.bar; // true

การสาธิตสด: http://jsfiddle.net/6Xq3P/

ตัวCustomสร้างเป็นตัวแทนของต้นแบบใหม่ ergo Custom.prototypeวัตถุมีคุณสมบัติใหม่ทั้งหมดที่คุณต้องการใช้กับวัตถุดั้งเดิมของคุณ

ภายในตัวCustomสร้างคุณเพียงแค่คัดลอกคุณสมบัติทั้งหมดจากวัตถุดั้งเดิมไปยังวัตถุอินสแตนซ์ใหม่

อ็อบเจ็กต์อินสแตนซ์ใหม่นี้มีคุณสมบัติทั้งหมดจากอ็อบเจ็กต์ดั้งเดิม (ถูกคัดลอกไปยังอ็อบเจ็กต์ภายในคอนสตรัคเตอร์) และคุณสมบัติใหม่ทั้งหมดที่กำหนดไว้ภายในCustom.prototype(เนื่องจากอ็อบเจ็กต์ใหม่เป็นCustomอินสแตนซ์)


3

คุณไม่สามารถเปลี่ยนต้นแบบของออบเจ็กต์ JavaScript ที่สร้างอินสแตนซ์แล้วด้วยวิธีข้ามเบราว์เซอร์ ดังที่คนอื่น ๆ กล่าวถึงตัวเลือกของคุณ ได้แก่ :

  1. เปลี่ยนไม่ได้มาตรฐาน / ข้ามเบราว์เซอร์__proto__คุณสมบัติ
  2. คัดลอกคุณสมบัติของวัตถุไปยังวัตถุใหม่

ไม่ได้ยอดเยี่ยมเป็นพิเศษโดยเฉพาะอย่างยิ่งหากคุณต้องวนซ้ำวัตถุเป็นวัตถุภายในเพื่อเปลี่ยนต้นแบบทั้งหมดอย่างมีประสิทธิภาพ

ทางเลือกในการตอบคำถาม

ฉันจะดูที่เป็นนามธรรมมากขึ้นเกี่ยวกับฟังก์ชันการทำงานที่คุณต้องการ

โดยพื้นฐานแล้วต้นแบบ / วิธีการอนุญาตให้ใช้วิธีการจัดกลุ่มฟังก์ชันตามวัตถุ
แทนที่จะเขียน

function trim(x){ /* implementation */ }
trim('   test   ');

ที่คุณเขียน

'   test  '.trim();

ไวยากรณ์ข้างต้นได้รับการบัญญัติศัพท์คำว่า OOP เนื่องจากไวยากรณ์ object.method () ข้อได้เปรียบหลักของ OOP ที่เหนือกว่าการเขียนโปรแกรมเชิงฟังก์ชันแบบเดิม ได้แก่ :

  1. ชื่อวิธีการสั้น ๆ และตัวแปรน้อยลงobj.replace('needle','replaced')เทียบกับต้องจำชื่อที่ชอบstr_replace ( 'foo' , 'bar' , 'subject')และตำแหน่งของตัวแปรต่างๆ
  2. method chaining ( string.trim().split().join()) เป็นวิธีที่ง่ายกว่าในการแก้ไขและเขียนฟังก์ชันที่ซ้อนกันjoin(split(trim(string))

ขออภัยใน JavaScript (ดังที่แสดงด้านบน) คุณไม่สามารถแก้ไขต้นแบบที่มีอยู่แล้วได้ Object.prototypeตามหลักการแล้วคุณสามารถแก้ไขได้เฉพาะ Object ที่ระบุข้างต้น แต่น่าเสียดายที่การแก้ไขObject.prototypeอาจทำให้สคริปต์เสียหาย (ส่งผลให้คุณสมบัติชนกันและลบล้าง)

ไม่มีพื้นกลางที่ใช้กันทั่วไประหว่างรูปแบบการเขียนโปรแกรมทั้ง 2 รูปแบบนี้และไม่มีวิธี OOP ในการจัดระเบียบฟังก์ชันแบบกำหนดเอง

UnlimitJSจัดเตรียมพื้นกลางที่ช่วยให้คุณกำหนดวิธีการที่กำหนดเอง หลีกเลี่ยง:

  1. การชนกันของคุณสมบัติเนื่องจากไม่ขยายต้นแบบของวัตถุ
  2. ยังคงอนุญาตให้ใช้ไวยากรณ์การเชื่อมโยง OOP
  3. เป็นสคริปต์ข้ามเบราว์เซอร์ 450 ไบต์ (IE6 +, Firefox 3.0 +, Chrome, Opera, Safari 3.0+) ที่ Unlimit ปัญหาการชนกันของคุณสมบัติต้นแบบของ JavaScript

การใช้รหัสของคุณด้านบนฉันจะสร้างเนมสเปซของฟังก์ชันที่คุณต้องการเรียกใช้กับวัตถุ

นี่คือตัวอย่าง:

var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}];

// define namespace with methods
var $ = {
  log:function(){
    console.log(this);
    return this;
  }[Unlimit](),
  alert:function(){
    alert(''+this);
  }[Unlimit]()
}


foo[$.log]()
   [$.log]()
   [$.alert]();

คุณสามารถอ่านเพิ่มเติมของตัวอย่างที่นี่UnlimitJS โดยทั่วไปเมื่อคุณเรียก[Unlimit]()ใช้ฟังก์ชันจะอนุญาตให้เรียกใช้ฟังก์ชันเป็นวิธีการบนวัตถุ เปรียบเสมือนพื้นที่ตรงกลางระหว่าง OOP และถนนที่ใช้งานได้


2

คุณไม่สามารถเปลี่ยนการ[[prototype]]อ้างอิงของวัตถุที่สร้างไว้แล้วเท่าที่ฉันรู้ คุณสามารถเปลี่ยนคุณสมบัติต้นแบบของฟังก์ชันคอนสตรัคเตอร์ดั้งเดิมได้ แต่ตามที่คุณได้แสดงความคิดเห็นไปแล้วคอนสตรัคเตอร์นั้นคือObjectและการแก้ไขโครงสร้าง JS หลักเป็นสิ่งที่ไม่ดี

คุณสามารถสร้างวัตถุพร็อกซีของวัตถุที่สร้างขึ้นซึ่งใช้ฟังก์ชันเพิ่มเติมที่คุณต้องการได้ คุณยังสามารถจับคู่วิธีการและพฤติกรรมเพิ่มเติมได้โดยกำหนดให้กับวัตถุที่เป็นปัญหาโดยตรง

บางทีคุณอาจได้รับสิ่งที่ต้องการด้วยวิธีอื่นหากคุณยินดีที่จะเข้าหาจากมุมที่แตกต่าง: คุณต้องทำอะไรที่เกี่ยวข้องกับการยุ่งกับต้นแบบ?


ใครสามารถแสดงความคิดเห็นเกี่ยวกับความถูกต้องของสิ่งนี้?
Vivian River

ดูเหมือนว่าจะขึ้นอยู่กับjsfiddle ที่น่ากลัวนี้ซึ่งคุณสามารถปรับเปลี่ยนต้นแบบของวัตถุที่มีอยู่ได้โดยการแก้ไข__proto__คุณสมบัติของมัน นี้จะทำงานในเบราว์เซอร์ที่สนับสนุน__proto__สัญกรณ์ซึ่งเป็น Chrome และ Firefox และจะได้รับการเลิกใช้ ดังนั้นในระยะสั้นคุณสามารถเปลี่ยน[[prototype]]วัตถุได้ แต่คุณอาจไม่ควร
Nick Husher

1

ถ้าคุณรู้จักต้นแบบทำไมไม่ฉีดลงในโค้ดล่ะ?

var foo = new MyPrototype(<%= MyData %>);

ดังนั้นเมื่อข้อมูลถูกทำให้เป็นอนุกรมคุณจะได้รับ

var foo = new MyPrototype([{"A":"1","B":"2"},{"X":"7","Y":"8"}]);

ตอนนี้คุณต้องการเพียงตัวสร้างที่รับอาร์เรย์เป็นอาร์กิวเมนต์


0

ไม่มีทางสืบทอดจากArrayหรือ "คลาสย่อย" ได้จริงๆ

สิ่งที่คุณทำได้คือสิ่งนี้ ( คำเตือน: FESTERING CODE AHEAD ):

function Foo(arr){
  [].push.apply(this, arr)
}
Foo.prototype = []
Foo.prototype.something = 123

var foo = new Foo(<%=MyData %>)

foo.length // => 2
foo[0] // => {"A":"1","B":"2"}
foo.something // => 123

วิธีนี้ใช้งานได้ แต่จะสร้างปัญหาให้กับทุกคนที่ข้ามเส้นทางของมัน (ดูเหมือนอาร์เรย์ แต่สิ่งต่างๆจะผิดพลาดหากคุณพยายามจัดการ)

ทำไมคุณไม่ไปเส้นทางที่มีเหตุผลและเพิ่มวิธีการ / คุณสมบัติโดยตรงfooหรือใช้ตัวสร้างและบันทึกอาร์เรย์ของคุณเป็นคุณสมบัติ

function Foo(arr){
  this.items = arr
}
Foo.prototype = {
  someMethod : function(){ ... }
  //...
}

var foo = new Foo(<%=MyData %>)
foo.items // => [{"A":"1","B":"2"},{"X":"7","Y":"8"}]

0

หากคุณต้องการสร้างต้นแบบทันทีนี่เป็นวิธีหนึ่ง

function OntheFlyProto (info){
    this.items = info;
    this.y =-1;
    for(var i = 0; i < this.items.length ; i++){
        OntheFlyProto.prototype["get"+this.items[i].name] = function (){
            this.y++;
            return this.items[this.y].value;
        }
    }
}

var foo = [{name:"one", value:1},{name:"two", value:2}];
v = new OntheFlyProto(foo);

-1
foo.prototype.myFunction = function(){alert("me");}

ไม่คุณทำไม่ได้ นั่นเป็นคุณสมบัติคงที่
SLaks

@SLaks prototypeเป็นสถิต? ฉันไม่แน่ใจว่าคุณหมายถึงอะไร
Šime Vidas

1
prototypeเป็นคุณสมบัติของฟังก์ชันไม่ใช่วัตถุ Object.prototypeมีอยู่; {}.prototypeไม่
SLaks

หากคุณไม่สนใจเกี่ยวกับความเข้ากันได้ของเบราว์เซอร์คุณสามารถใช้Object.getPrototypeOf(foo)เพื่อรับวัตถุต้นแบบตัวสร้าง คุณสามารถปรับเปลี่ยนคุณสมบัติเพื่อแก้ไขต้นแบบของวัตถุ ใช้งานได้เฉพาะในเบราว์เซอร์ล่าสุดไม่สามารถบอกคุณได้ว่าเป็นเบราว์เซอร์ใด
Nick Husher

@TeslaNick: คุณสามารถแก้ไขObject.prototypeได้โดยตรงเพราะเป็นไปได้มากว่าสิ่งที่Object.getPrototypeOf(foo)จะกลับมา ไม่ค่อยมีประโยชน์.
Wladimir Palant
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.