ทำไมการใช้คอนสตรัคเตอร์ท้อใจเมื่อสร้างต้นแบบ?


10

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

ตัวอย่างเช่น:

var Parent = function() { /* constructor business */ }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = /*** !! Some prototype object goes here !! ***/

คำถามของฉันถามเกี่ยวกับรหัสที่ควรไปในSome prototype object goes hereจุดที่ระบุในรหัสด้านบน สัญชาตญาณแรกของฉันคือสร้างอินสแตนซ์ของพาเรนต์ (เช่นnew Parent()) แต่ในความคิดเห็นต่อคำตอบนี่เป็นวิธีที่ปลอดภัยในการคัดลอกวัตถุต้นแบบหนึ่งไปยังวัตถุอื่นหรือไม่ ผู้ใช้หนึ่งคนเขียน:

ไม่อย่าใช้new bar()สำหรับวัตถุต้นแบบ!

(... ซึ่งเป็นความคิดเห็นที่ฉันได้เห็นในคำตอบและความคิดเห็น SO มากมาย แต่นี่เป็นเพียงตัวอย่างเดียวที่ฉันมีในขณะนี้)

ตัวเลือกอื่น ๆ คือการใช้เป็นObject.create(Parent.prototype) Child.prototypeเท่าที่ฉันรู้สิ่งนี้ยังสร้างParentอินสแตนซ์ใหม่แต่มันไม่เรียกใช้ตัวParentสร้าง

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

คำตอบ:


5

เพราะมันเป็นฟังก์ชั่นที่ไม่จำเป็นต้องเรียก newไม่แตกต่างจากการเรียกใช้ฟังก์ชันปกติใน Javascript

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

และคุณไม่ต้องการObject.createนี่ก็เพียงพอแล้ว:

function objectCreate( proto ) {
    function T(){}
    T.prototype = proto;
    return new T();
}

แต่นั่นเป็นวิธีObject.createการใช้งานจริง
Casey Chu

@CaseyChu ไม่ได้เลย และฉันพูดถึงมันเพราะในโพสต์ที่เชื่อมโยงบางคนบอกว่า " Object.createไม่ทำงานใน IE8" - ซึ่งเป็นเพียงความคิดเห็นที่ไร้ประโยชน์เมื่อคุณสามารถใช้มันสำหรับกรณีการใช้งานนี้ใน 2 วินาทีในเบราว์เซอร์ใด ๆ
Esailija

2

ตอนนี้ความเข้าใจของฉันได้ขยายออกไปเล็กน้อยฉันอยากจะสร้างคำตอบของ Esailijaด้วยตัวอย่างเฉพาะ:

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

ตัวอย่างเช่นสมมติว่าParentแต่ละรายการมีidชุดคุณสมบัติที่ไม่ซ้ำกันเป็นเวลาในการก่อสร้าง:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() { /* constructor business */ }
Child.prototype = new Parent();

นี้จะทำให้ทุก Childกรณีที่จะแบ่งปันต้นแบบเดียวidคุณสมบัติได้รับการถ่ายทอดจากคนหนึ่งและมีเพียงวัตถุที่ใช้เป็นnew Parent()Child.prototype

วิธีที่ดีกว่าสำหรับกรณีนี้คือใช้Object.createและเรียกผู้สร้างหลักโดยตรง (หากจำเป็น) ภายในตัวสร้างลูก:

var Parent = function() { this.id = Math.random(); }
Parent.prototype.parentProp = "some parent property";

var Child = function() {
    // run `this` through the Parent constructor function
    Parent.apply(this, arguments);
}
Child.prototype = Object.create(Parent.prototype);
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.