ทั้งตัวอย่างรหัสที่คุณแสดงในคำถามของคุณใช้ประโยชน์จากการสืบทอดต้นแบบ ในความเป็นจริงโค้ดเชิงวัตถุใด ๆ ที่คุณเขียนใน JavaScript เป็นกระบวนทัศน์ของการสืบทอดต้นแบบ JavaScript ไม่มีการสืบทอดแบบคลาสสิก สิ่งนี้ควรทำให้ชัดเจนขึ้นเล็กน้อย:
Inheritance
|
+-----------------------------+
| |
v v
Prototypal Classical
|
+------------------------------+
| |
v v
Prototypal Pattern Constructor Pattern
ดังที่คุณเห็นการถ่ายทอดทางพันธุกรรมและการสืบทอดแบบคลาสสิกเป็นสองกระบวนทัศน์ที่แตกต่างกันของการถ่ายทอดทางพันธุกรรม บางภาษาเช่น Self, Lua และ JavaScript สนับสนุนการสืบทอดต้นแบบ อย่างไรก็ตามภาษาส่วนใหญ่เช่น C ++, Java และ C # รองรับการสืบทอดแบบคลาสสิก
ภาพรวมโดยย่อของการเขียนโปรแกรมเชิงวัตถุ
ทั้งการสืบทอดต้นแบบและการสืบทอดคลาสสิกเป็นกระบวนทัศน์การเขียนโปรแกรมเชิงวัตถุ (กล่าวคือจัดการกับวัตถุ) ออบเจ็กต์เป็นเพียงนามธรรมที่ห่อหุ้มคุณสมบัติของเอนทิตีในโลกแห่งความเป็นจริง (กล่าวคือเป็นตัวแทนของคำจริงในโปรแกรม) สิ่งนี้เรียกว่านามธรรม
Abstraction:การแสดงสิ่งต่างๆในโลกแห่งความเป็นจริงในโปรแกรมคอมพิวเตอร์
ในทางทฤษฎีแล้วสิ่งที่เป็นนามธรรมถูกกำหนดให้เป็น "แนวคิดทั่วไปที่เกิดจากการดึงคุณลักษณะทั่วไปจากตัวอย่างเฉพาะ" อย่างไรก็ตามเพื่อประโยชน์ของคำอธิบายนี้เราจะใช้คำจำกัดความดังกล่าวแทน
ตอนนี้วัตถุบางอย่างมีหลายอย่างที่เหมือนกัน ตัวอย่างเช่นจักรยานโคลนและ Harley Davidson มีหลายอย่างที่เหมือนกัน
จักรยานโคลน:
ฮาร์เลย์เดวิดสัน:
จักรยานโคลนและ Harley Davidson ต่างก็เป็นมอเตอร์ไซค์ ดังนั้นจักรยานจึงเป็นลักษณะทั่วไปของทั้งจักรยานโคลนและ Harley Davidson
Bike
|
+---------------------------------+
| |
v v
Mud Bike Harley Davidson
ในตัวอย่างข้างต้นจักรยานโคลนและ Harley Davidson ล้วนเป็นนามธรรม อย่างไรก็ตามจักรยานเป็นสิ่งที่เป็นนามธรรมโดยทั่วไปของจักรยานโคลนและ Harley Davidson (กล่าวคือทั้งจักรยานโคลนและ Harley Davidson เป็นจักรยานประเภทเฉพาะ)
ลักษณะทั่วไป:สิ่งที่เป็นนามธรรมของนามธรรมที่เฉพาะเจาะจงมากขึ้น
ในการเขียนโปรแกรมเชิงวัตถุเราสร้างออบเจ็กต์ (ซึ่งเป็นนามธรรมของเอนทิตีในโลกแห่งความเป็นจริง) และเราใช้คลาสหรือต้นแบบเพื่อสร้างภาพรวมของวัตถุเหล่านี้ ลักษณะทั่วไปถูกสร้างขึ้นโดยการสืบทอด จักรยานเป็นลักษณะทั่วไปของจักรยานโคลน ดังนั้นจักรยานโคลนจึงสืบทอดมาจากจักรยาน
การเขียนโปรแกรมเชิงวัตถุแบบคลาสสิก
ในการเขียนโปรแกรมเชิงวัตถุแบบคลาสสิกเรามีนามธรรม 2 ประเภท ได้แก่ คลาสและอ็อบเจ็กต์ วัตถุดังที่กล่าวไว้ก่อนหน้านี้เป็นสิ่งที่เป็นนามธรรมขององค์กรในโลกแห่งความเป็นจริง ในทางกลับกันคลาสเป็นนามธรรมของอ็อบเจ็กต์หรือคลาสอื่น (กล่าวคือเป็นลักษณะทั่วไป) ตัวอย่างเช่นพิจารณา:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | Man | Class of object johnDoe. |
| 3 | Human | Superclass of class Man. |
+----------------------+----------------+---------------------------------------+
ดังที่คุณเห็นในภาษาการเขียนโปรแกรมเชิงวัตถุคลาสสิกออบเจ็กต์เป็นเพียงนามธรรม (กล่าวคืออ็อบเจ็กต์ทั้งหมดมีระดับนามธรรมเท่ากับ 1) และคลาสเป็นเพียงการสรุปทั่วไปเท่านั้น (กล่าวคือคลาสทั้งหมดมีระดับนามธรรมมากกว่า 1)
อ็อบเจ็กต์ในภาษาโปรแกรมเชิงวัตถุคลาสสิกสามารถสร้างได้โดยการสร้างอินสแตนซ์คลาสเท่านั้น:
class Human {
// ...
}
class Man extends Human {
// ...
}
Man johnDoe = new Man();
ในการสรุปในภาษาโปรแกรมเชิงวัตถุคลาสสิกออบเจ็กต์เป็นนามธรรมของเอนทิตีในโลกแห่งความเป็นจริงและคลาสคือการสรุป (เช่น abstractions ของอ็อบเจ็กต์หรือคลาสอื่น ๆ )
ดังนั้นเมื่อระดับของสิ่งที่เป็นนามธรรมเพิ่มขึ้นเอนทิตีจึงมีความกว้างมากขึ้นและเมื่อระดับของสิ่งที่เป็นนามธรรมลดลงเอนทิตีก็มีความเฉพาะเจาะจงมากขึ้น ในแง่นี้ระดับของนามธรรมจึงคล้ายคลึงกับมาตราส่วนตั้งแต่เอนทิตีเฉพาะเจาะจงมากขึ้นไปจนถึงเอนทิตีทั่วไป
Prototypal Object-Oriented Programming
ภาษาโปรแกรมเชิงวัตถุ Prototypal นั้นง่ายกว่าภาษาการเขียนโปรแกรมเชิงวัตถุแบบคลาสสิกมากเนื่องจากในการเขียนโปรแกรมเชิงวัตถุต้นแบบเรามีนามธรรมเพียงประเภทเดียวเท่านั้น (เช่นวัตถุ) ตัวอย่างเช่นพิจารณา:
+----------------------+----------------+---------------------------------------+
| Level of Abstraction | Name of Entity | Comments |
+----------------------+----------------+---------------------------------------+
| 0 | John Doe | Real World Entity. |
| 1 | johnDoe | Variable holding object. |
| 2 | man | Prototype of object johnDoe. |
| 3 | human | Prototype of object man. |
+----------------------+----------------+---------------------------------------+
ดังที่คุณเห็นในภาษาการเขียนโปรแกรมเชิงวัตถุต้นแบบออบเจ็กต์เป็นนามธรรมของเอนทิตีในโลกแห่งความเป็นจริง (ซึ่งในกรณีนี้จะเรียกว่าวัตถุ) หรือวัตถุอื่น ๆ (ซึ่งในกรณีนี้จะเรียกว่าต้นแบบของวัตถุเหล่านั้นที่เป็นนามธรรม) ดังนั้นต้นแบบจึงเป็นลักษณะทั่วไป
อ็อบเจ็กต์ในภาษาการเขียนโปรแกรมเชิงวัตถุต้นแบบอาจถูกสร้างขึ้นได้ทั้งแบบ ex-nihilo (เช่นไม่มีอะไรเลย) หรือจากอ็อบเจ็กต์อื่น (ซึ่งกลายเป็นต้นแบบของอ็อบเจ็กต์ที่สร้างขึ้นใหม่):
var human = {};
var man = Object.create(human);
var johnDoe = Object.create(man);
ในความเห็นที่ต่ำต้อยของฉันภาษาโปรแกรมเชิงวัตถุต้นแบบมีพลังมากกว่าภาษาโปรแกรมเชิงวัตถุแบบคลาสสิกเนื่องจาก:
- สิ่งที่เป็นนามธรรมมีเพียงประเภทเดียว
- การสรุปเป็นเพียงวัตถุ
ถึงตอนนี้คุณต้องตระหนักถึงความแตกต่างระหว่างการสืบทอดแบบคลาสสิกและการถ่ายทอดทางพันธุกรรมแบบต้นแบบ การสืบทอดคลาสสิก จำกัด เฉพาะคลาสที่สืบทอดมาจากคลาสอื่น อย่างไรก็ตามการสืบทอดต้นแบบไม่เพียง แต่รวมถึงต้นแบบที่สืบทอดมาจากต้นแบบอื่น ๆ เท่านั้น แต่ยังรวมถึงวัตถุที่สืบทอดมาจากต้นแบบด้วย
Isomorphism ระดับต้นแบบ
คุณต้องสังเกตว่าต้นแบบและคลาสนั้นคล้ายกันมาก นั่นคือเรื่องจริง พวกเขาเป็น. ในความเป็นจริงมันคล้ายกันมากจนคุณสามารถใช้ต้นแบบในการจำลองคลาสได้:
function CLASS(base, body) {
if (arguments.length < 2) body = base, base = Object.prototype;
var prototype = Object.create(base, {new: {value: create}});
return body.call(prototype, base), prototype;
function create() {
var self = Object.create(prototype);
return prototype.hasOwnProperty("constructor") &&
prototype.constructor.apply(self, arguments), self;
}
}
การใช้CLASS
ฟังก์ชันข้างต้นคุณสามารถสร้างต้นแบบที่ดูเหมือนคลาสได้:
var Human = CLASS(function () {
var milliseconds = 1
, seconds = 1000 * milliseconds
, minutes = 60 * seconds
, hours = 60 * minutes
, days = 24 * hours
, years = 365.2425 * days;
this.constructor = function (name, sex, dob) {
this.name = name;
this.sex = sex;
this.dob = dob;
};
this.age = function () {
return Math.floor((new Date - this.dob) / years);
};
});
var Man = CLASS(Human, function (Human) {
this.constructor = function (name, dob) {
Human.constructor.call(this, name, "male", dob);
if (this.age() < 18) throw new Error(name + " is a boy, not a man!");
};
});
var johnDoe = Man.new("John Doe", new Date(1970, 0, 1));
อย่างไรก็ตามการย้อนกลับไม่เป็นความจริง (กล่าวคือคุณไม่สามารถใช้คลาสเพื่อสร้างโมเดลต้นแบบได้) เนื่องจากต้นแบบเป็นวัตถุ แต่คลาสไม่ใช่วัตถุ เป็นนามธรรมที่แตกต่างกันอย่างสิ้นเชิง
ข้อสรุป
ในผลรวมที่เราได้เรียนรู้ว่าเป็นนามธรรมเป็น"แนวคิดทั่วไปที่เกิดขึ้นจากการสกัดคุณลักษณะทั่วไปจากตัวอย่างที่เฉพาะเจาะจง"และทั่วไปที่เป็น"นามธรรมของนามธรรมเฉพาะเจาะจงมากขึ้น" นอกจากนี้เรายังได้เรียนรู้เกี่ยวกับความแตกต่างระหว่างการถ่ายทอดทางพันธุกรรมแบบต้นแบบและแบบคลาสสิกและวิธีที่ทั้งสองเป็นสองหน้าของเหรียญเดียวกัน
ในบันทึกการพรากจากกันฉันอยากจะตั้งข้อสังเกตว่ามีสองรูปแบบของการสืบทอดต้นแบบ: รูปแบบต้นแบบและรูปแบบตัวสร้าง รูปแบบของต้นแบบเป็นรูปแบบที่ยอมรับได้ของการถ่ายทอดทางพันธุกรรมของต้นแบบในขณะที่รูปแบบตัวสร้างใช้เพื่อทำให้การสืบทอดของต้นแบบมีลักษณะเหมือนการสืบทอดแบบคลาสสิก โดยส่วนตัวแล้วฉันชอบรูปแบบต้นแบบมากกว่า
ป.ล. ฉันเป็นคนที่เขียนบล็อกโพสต์ " Why Prototypal Inheritance Matters " และตอบคำถามว่า " ประโยชน์ของการถ่ายทอดทางพันธุกรรมของต้นแบบในรูปแบบคลาสสิก " คำตอบของฉันคือคำตอบที่ได้รับการยอมรับ