TLDR; ไม่จำเป็นอย่างยิ่ง แต่อาจจะช่วยได้ในระยะยาวและแม่นยำยิ่งขึ้น
หมายเหตุ: แก้ไขมากเป็นคำตอบก่อนหน้าของฉันถูกเขียนสับสนและมีข้อผิดพลาดบางอย่างที่ฉันพลาดในการเร่งรีบของฉันที่จะตอบ ขอบคุณผู้ที่ชี้ให้เห็นข้อผิดพลาดอย่างมหันต์
โดยพื้นฐานแล้วการวางสายย่อยให้ถูกต้องใน Javascript เมื่อเรา subclass เราต้องทำสิ่งที่ขี้ขลาดเพื่อให้แน่ใจว่าการมอบหมายต้นแบบทำงานอย่างถูกต้องรวมถึงการเขียนทับprototype
วัตถุ การเขียนทับprototype
วัตถุรวมถึงconstructor
ดังนั้นเราจึงจำเป็นต้องแก้ไขการอ้างอิง
เรามาดูกันว่า 'คลาส' ใน ES5 ทำงานอย่างไร
สมมติว่าคุณมีฟังก์ชั่นการสร้างและต้นแบบของมัน:
//Constructor Function
var Person = function(name, age) {
this.name = name;
this.age = age;
}
//Prototype Object - shared between all instances of Person
Person.prototype = {
species: 'human',
}
เมื่อคุณเรียกนวกรรมิกเพื่อสร้างอินสแตนซ์ให้พูดว่าAdam
:
// instantiate using the 'new' keyword
var adam = new Person('Adam', 19);
new
คำหลักเรียกด้วย 'คน' โดยทั่วไปจะเรียกใช้ตัวสร้างคนที่มีบรรทัดเพิ่มเติมไม่กี่รหัส:
function Person (name, age) {
// This additional line is automatically added by the keyword 'new'
// it sets up the relationship between the instance and the prototype object
// So that the instance will delegate to the Prototype object
this = Object.create(Person.prototype);
this.name = name;
this.age = age;
return this;
}
/* So 'adam' will be an object that looks like this:
* {
* name: 'Adam',
* age: 19
* }
*/
ถ้าเราconsole.log(adam.species)
การค้นหาจะล้มเหลวที่adam
อินสแตนซ์และมองขึ้นห่วงโซ่ prototypal ของมัน.prototype
ซึ่งเป็นPerson.prototype
- และPerson.prototype
มีคุณสมบัติเพื่อให้การค้นหาจะประสบความสำเร็จใน.species
Person.prototype
จากนั้นจะเข้าสู่ระบบ'human'
จากนั้นจะเข้าสู่ระบบ
ที่นี่ได้อย่างถูกต้องจะชี้ไปที่Person.prototype.constructor
Person
ดังนั้นตอนนี้ส่วนที่น่าสนใจที่เรียกว่า 'subclassing' หากเราต้องการสร้างStudent
ชั้นเรียนซึ่งเป็นคลาสย่อยของPerson
ชั้นเรียนที่มีการเปลี่ยนแปลงเพิ่มเติมบางอย่างเราจะต้องตรวจสอบให้แน่ใจว่าStudent.prototype.constructor
คะแนนของนักเรียนนั้นถูกต้อง
มันไม่ได้ทำด้วยตัวเอง เมื่อคุณคลาสย่อยโค้ดจะมีลักษณะดังนี้:
var Student = function(name, age, school) {
// Calls the 'super' class, as every student is an instance of a Person
Person.call(this, name, age);
// This is what makes the Student instances different
this.school = school
}
var eve = new Student('Eve', 20, 'UCSF');
console.log(Student.prototype); // this will be an empty object: {}
การเรียกnew Student()
ที่นี่จะส่งคืนวัตถุที่มีคุณสมบัติทั้งหมดที่เราต้องการ นี่ถ้าเราตรวจสอบก็จะกลับมาeve instanceof Person
false
หากเราพยายามเข้าถึงeve.species
มันจะกลับมาundefined
มันจะกลับมา
ในคำอื่น ๆ ที่เราจำเป็นต้องลวดขึ้นคณะผู้แทนเพื่อให้eve instanceof Person
ผลตอบแทนที่แท้จริงและเพื่อให้กรณีของStudent
ผู้รับมอบสิทธิ์อย่างถูกต้องแล้วStudent.prototype
Person.prototype
แต่เนื่องจากเราเรียกมันด้วยnew
คำหลักโปรดจำไว้ว่าการเรียกนั้นเพิ่มอะไร มันจะเรียกObject.create(Student.prototype)
ซึ่งเป็นวิธีการที่เราตั้งค่าความสัมพันธ์ระหว่าง delegational และStudent
Student.prototype
โปรดทราบว่าตอนนี้Student.prototype
ว่างเปล่า ดังนั้นการค้นหา.species
อินสแตนซ์ของStudent
จะล้มเหลวเนื่องจากมอบหมายให้เท่านั้น Student.prototype
และ.species
ไม่มีคุณสมบัติอยู่Student.prototype
คุณสมบัติที่ไม่ได้อยู่ใน
เมื่อเราทำกำหนดStudent.prototype
ไปObject.create(Person.prototype)
, Student.prototype
ตัวเองแล้วมอบหมายให้Person.prototype
และมองขึ้นไปeve.species
จะกลับมาhuman
ในขณะที่เราคาดหวัง สมมุติว่าเราต้องการให้สืบทอดมาจาก Student.prototype และ Person.prototype ดังนั้นเราต้องแก้ไขทั้งหมดนี้
/* This sets up the prototypal delegation correctly
*so that if a lookup fails on Student.prototype, it would delegate to Person's .prototype
*This also allows us to add more things to Student.prototype
*that Person.prototype may not have
*So now a failed lookup on an instance of Student
*will first look at Student.prototype,
*and failing that, go to Person.prototype (and failing /that/, where do we think it'll go?)
*/
Student.prototype = Object.create(Person.prototype);
ตอนนี้คณะทำงาน แต่เรากำลังเขียนทับกับของStudent.prototype
Person.prototype
ดังนั้นถ้าเราเรียกStudent.prototype.constructor
มันจะชี้ไปแทนPerson
นี่คือเหตุผลที่เราจำเป็นต้องแก้ไขStudent
// Now we fix what the .constructor property is pointing to
Student.prototype.constructor = Student
// If we check instanceof here
console.log(eve instanceof Person) // true
ใน ES5 constructor
คุณสมบัติของเราเป็นข้อมูลอ้างอิงที่อ้างอิงถึงฟังก์ชั่นที่เราเขียนด้วยความตั้งใจที่จะเป็น 'ผู้สร้าง' นอกเหนือจากสิ่งที่new
คำหลักให้เรา, นวกรรมิกก็เป็นฟังก์ชั่น 'ธรรมดา'
ใน ES6 constructor
ตอนนี้ถูกสร้างขึ้นในวิธีที่เราเขียนคลาส - ซึ่งเป็นวิธีการเมื่อเราประกาศคลาส นี่เป็นน้ำตาลเชิงประโยคเพียง แต่ให้ความสะดวกกับเราเช่นการเข้าถึงsuper
เมื่อเราขยายคลาสที่มีอยู่ ดังนั้นเราจะเขียนโค้ดด้านบนดังนี้:
class Person {
// constructor function here
constructor(name, age) {
this.name = name;
this.age = age;
}
// static getter instead of a static property
static get species() {
return 'human';
}
}
class Student extends Person {
constructor(name, age, school) {
// calling the superclass constructor
super(name, age);
this.school = school;
}
}