แม้ว่า JavaScript เป็นภาษาที่มุ่งเน้นวัตถุ แต่กลไกการสืบทอดของมันนั้นแตกต่างจากภาษาที่มุ่งเน้นวัตถุแบบดั้งเดิมตั้งแต่เริ่มก่อตั้ง มันเป็นกลไกการสืบทอดที่ใช้ต้นแบบ อย่างไรก็ตามภายใต้กลไกนี้ยังมีวิธีการใช้งานที่แตกต่างกันสำหรับการสืบทอด
วิธีที่ 1: มรดกแบบคลาสสิก
มรดกที่เรียกว่าคลาสหมายถึงการเลียนแบบวิธีการสืบทอดของภาษาเชิงวัตถุแบบดั้งเดิม ทั้งมรดกและฝ่ายที่สืบทอดมาคือ "ชั้นเรียน" รหัสมีดังนี้:
ก่อนกำหนดคลาสแม่ (หรือ superclass):
ฟังก์ชันบุคคล (ชื่อ) {this.name = name; } person.prototype.getName = function () {return this.name; -แอตทริบิวต์ของบุคคลระดับพาเรนต์ถูกกำหนดไว้ในตัวสร้างซึ่งสามารถมั่นใจได้ว่าแอตทริบิวต์ชื่อของคลาสย่อยที่สืบทอดมานั้นไม่ได้แชร์แอตทริบิวต์นี้กับมัน แต่เป็นของคลาสย่อยแยกกัน วิธีการ getName นั้นติดตั้งบนต้นแบบเพื่อให้มีหลายอินสแตนซ์ของคลาสย่อยที่สืบทอดมาเพื่อแบ่งปันวิธีการนี้เพื่อให้หน่วยความจำสามารถบันทึกได้ (สำหรับหลาย ๆ กรณีทุกครั้งที่มีอินสแตนซ์ใหม่ออกมา
กำหนดวิธีการสืบทอดขยายดังนี้:
ฟังก์ชันขยาย (subclass, superclass) {var f = function () {}; f.prototype = superclass.prototype; subclass.prototype = new f (); subclass.prototype.constructor = subclass; subclass.superclass = superclass.prototype; if (superclass.prototype.constructor == object.prototype.constructor) {superclass.prototype.constructor = superclass; -ในวิธีนี้ให้สร้างคลาส F ใหม่ให้ปล่อยให้ต้นแบบเป็นต้นแบบของคลาสแม่และปล่อยให้ต้นแบบของจุดย่อยเป็นอินสแตนซ์ของคลาส F ดังนั้นจึงบรรลุวัตถุประสงค์ในการสืบทอดคลาสแม่ ในเวลาเดียวกันเนื่องจากต้นแบบของคลาสย่อยได้รับการแก้ไขแอตทริบิวต์ตัวสร้างของต้นแบบที่แก้ไขจะถูกชี้ไปที่คลาสย่อยเพื่อให้มีฟังก์ชั่นคอนสตรัคเตอร์และในเวลาเดียวกันคลาสย่อยสามารถติดตั้งแอตทริบิวต์ซูเปอร์คลาส คลาสย่อยสามารถเรียกคลาสพาเรนต์ผ่านคุณสมบัตินี้ดังนั้นการสร้างความสัมพันธ์ระหว่างคลาสย่อยและคลาสแม่
กำหนดผู้เขียน subclass เพื่อสืบทอดบุคคลระดับผู้ปกครองดังต่อไปนี้:
ฟังก์ชั่นผู้แต่ง (ชื่อ, หนังสือ) {ผู้แต่ง. superclass.constructor.call (ชื่อนี้); this.book = หนังสือ; } ขยาย (ผู้แต่งบุคคล); Author.prototype.getBooks = function () {return this.book; -ที่นี่ตัวสร้างของคลาสแม่ถูกเรียกผ่านแอตทริบิวต์ superclass ในตัวสร้างของคลาสย่อย ในเวลาเดียวกันวิธีการโทรใช้เพื่อแปลงตัวชี้ของการโทรวิธีนี้เพื่อให้ผู้เขียน subclass มี (สืบทอด) คุณสมบัติของคลาสแม่และคลาสย่อยยังมีหนังสือแอตทริบิวต์ของตัวเอง ดังนั้นหนังสือพารามิเตอร์จึงถูกกำหนดให้กับหนังสือแอตทริบิวต์ในคอนสตรัคเตอร์เพื่อให้บรรลุวัตถุประสงค์ของการก่อสร้าง ใช้ฟังก์ชั่นขยายเพื่อสืบทอดคุณสมบัติและวิธีการบนต้นแบบบุคคลระดับพาเรนต์ (ที่จริงแล้วมีเพียงวิธีการที่ได้รับการสืบทอดเพราะเราเพิ่งติดตั้งวิธีการไปยังต้นแบบก่อนและคุณสมบัติที่กำหนดไว้ในคอนสตรัคเตอร์) ในเวลาเดียวกันผู้เขียนมีวิธีการของตัวเอง getbooks ติดตั้งบนต้นแบบที่สอดคล้องกันเพื่อให้บรรลุวัตถุประสงค์ของการขยายตัวต่อไปบนพื้นฐานของการสืบทอด
วิธีการสืบทอดนี้เห็นได้ชัดว่าเป็นประเภทการสืบทอดที่คล้ายกับภาษาเชิงวัตถุแบบดั้งเดิม ข้อได้เปรียบคือมันเป็นเรื่องง่ายสำหรับโปรแกรมเมอร์ที่คุ้นเคยกับแนวคิดเชิงวัตถุแบบดั้งเดิม ข้อเสียคือกระบวนการค่อนข้างยุ่งยากและการใช้หน่วยความจำมีขนาดใหญ่กว่าเล็กน้อยเนื่องจากคลาสย่อยยังมีตัวสร้างและต้นแบบของตัวเองและคุณลักษณะของคลาสย่อยและคลาสแม่จะแยกได้อย่างสมบูรณ์ แม้ว่าทั้งสองจะมีค่าเท่ากันพวกเขาไม่สามารถแชร์หน่วยความจำเดียวกันได้
วิธีที่ 2: การสืบทอดต้นแบบ
ก่อนอื่นกำหนดคลาสหลัก ที่นี่เราจะไม่เลียนแบบการใช้ตัวสร้างเพื่อกำหนด แต่กำหนดวัตถุโดยตรงในรูปแบบของตัวอักษรวัตถุซึ่งเป็นคลาสหลัก
var person = {ชื่อ: 'ชื่อเริ่มต้น', getName: function () {return this.name; -เช่นเดียวกับวิธีแรกวัตถุมีชื่อคุณสมบัติและวิธีการ getName
จากนั้นกำหนดวิธีการโคลนนิ่งเพื่อใช้การสืบทอดของคลาสย่อยไปยังคลาสหลักดังต่อไปนี้:
ฟังก์ชั่นโคลน (obj) {ฟังก์ชั่น f () {} f.prototype = obj; คืน F () ใหม่; -วิธีการโคลนนิ่งสร้างวัตถุใหม่ชี้ต้นแบบของวัตถุไปยังคลาสแม่นั่นคือพารามิเตอร์ OBJ และส่งคืนวัตถุในเวลาเดียวกัน
ในที่สุดคลาสย่อยจะสืบทอดคลาสหลักผ่านฟังก์ชันการโคลนนิ่งดังนี้:
VAR Author = Clone (บุคคล); uther.book = ['JavaScript']; Author.showbook = function () {return this.book; -ที่นี่มีการกำหนดคลาสย่อยและบุคคลระดับพาเรนต์ได้รับการสืบทอดผ่านฟังก์ชั่นโคลนและหนังสือแอตทริบิวต์ถูกขยายออกไปและมีการขยายหนังสือวิธีการ ที่นี่ subclass ยังมีชื่อแอตทริบิวต์ แต่มันเหมือนกับค่าชื่อของคลาสแม่ดังนั้นจึงไม่ได้ถูกแทนที่ หากแตกต่างกันคุณสามารถใช้มันได้
uther.name = 'ชื่อใหม่'; เขียนทับคุณสมบัตินี้เพื่อรับค่าแอตทริบิวต์ชื่อใหม่ของคลาสย่อย
การสืบทอดต้นแบบนี้ง่ายกว่าและเป็นธรรมชาติมากกว่าการสืบทอดคลาส ในเวลาเดียวกันหากแอตทริบิวต์ของคลาสย่อยและค่าแอตทริบิวต์คลาสแม่จะเหมือนกันและสามารถแก้ไขได้พวกเขาจะแชร์พื้นที่หน่วยความจำเดียวกัน ตัวอย่างเช่นแอตทริบิวต์ชื่อด้านบนเป็นเรื่องยากที่จะเข้าใจสำหรับโปรแกรมเมอร์ที่คุ้นเคยกับโปรแกรมเชิงวัตถุแบบดั้งเดิม หากเลือกทั้งสองวิธีนี้จะดีกว่าอย่างไม่ต้องสงสัย
เนื่องจาก JavaScript ใช้วิธีการตามต้นแบบเพื่อใช้การสืบทอดและต้นแบบของแต่ละวัตถุสามารถชี้ไปที่อินสแตนซ์ของคลาสเฉพาะ (ไม่ใช่หลายอินสแตนซ์) วิธีการใช้มรดกหลายอย่าง (นั่นคือคลาสมีวิธีการและคุณลักษณะของหลายคลาสในเวลาเดียวกัน
ในรูปแบบการออกแบบ JavaScript จะได้รับคลาส mixin:
ขั้นแรกให้กำหนดคลาสยาสลบเพื่อบันทึกวิธีการและแอตทริบิวต์ที่ใช้กันทั่วไป วิธีการและแอตทริบิวต์เหล่านี้สามารถเพิ่มไปยังคลาสอื่น ๆ ผ่านการขยายตัวเพื่อให้คลาสที่เพิ่มเข้ามามีวิธีการและคุณลักษณะบางอย่างของคลาส หากมีการกำหนดและเพิ่มคลาสยาสลบหลายคลาสในชั้นเรียนในเวลาเดียวกันคลาสนั้นจะใช้ "การสืบทอดหลายครั้ง" ทางอ้อม จากแนวคิดนี้การใช้งานมีดังนี้:
คำจำกัดความของคลาสองค์ประกอบที่โดดเด่น:
var mixin = function () {}; mixin.prototype = {serialize: function () {var output = []; สำหรับ (คีย์ในนี้) {output.push (คีย์+":"+นี้ [คีย์]); } return output.join (','); -คลาสยาสลบมีวิธีการอนุกรมที่ใช้ในการสำรวจตัวเองส่งออกแอตทริบิวต์และค่าแอตทริบิวต์ของตัวเองและส่งคืนเป็นสตริงซึ่งคั่นด้วยเครื่องหมายจุลภาค
กำหนดวิธีการขยายเพื่อให้ชั้นเรียนมีคุณสมบัติหรือวิธีการของคลาสหลายกลุ่มหลังจากการขยายตัวดังนี้:
ฟังก์ชั่น Augment (TeamiveClass, GivingClass) {ถ้า (อาร์กิวเมนต์ [2]) {สำหรับ (var i = 2, len = arguments.length; i <len; i ++) {รับ class.prototype [อาร์กิวเมนต์ [i]] = Givingclass.prototype [อาร์กิวเมนต์ [i]]; }} else {สำหรับ (methodName ในการให้ class.prototype) {if (! teamiveClass.prototype [methodName]) {รับ class.prototype [methodName] = givingclass.prototype [methodName]; }}}}วิธีนี้มีพารามิเตอร์สองตัวโดยค่าเริ่มต้น พารามิเตอร์แรกยอมรับคลาสที่ขยายตัวพารามิเตอร์ที่สองคือคลาสเจือ (ใช้เพื่อขยายคลาสอื่น ๆ ) และอาจมีพารามิเตอร์อื่น ๆ หากมีพารามิเตอร์มากกว่าสองพารามิเตอร์พารามิเตอร์ที่ตามมาคือเมธอดหรือชื่อแอตทริบิวต์ซึ่งใช้เพื่อระบุว่าคลาสที่ขยายตัวต้องการที่จะสืบทอดแอตทริบิวต์หรือวิธีการที่ระบุของคลาสเจือ มิฉะนั้นแอตทริบิวต์และวิธีการทั้งหมดของคลาสเจือจะได้รับการสืบทอดโดยค่าเริ่มต้น ในฟังก์ชั่นนี้จะใช้สาขาแรกหากใช้เพื่อสืบทอดแอตทริบิวต์และวิธีการที่ระบุและสาขาอื่นเป็นกรณีที่แอตทริบิวต์และวิธีการทั้งหมดได้รับการสืบทอดโดยค่าเริ่มต้น สาระสำคัญของวิธีนี้คือการขยาย (เพิ่ม) คุณสมบัติและวิธีการบนต้นแบบของคลาสยาสลบองค์ประกอบไปยังต้นแบบของคลาสที่ขยายตัวเพื่อให้มีคุณสมบัติและวิธีการของคลาสยาสลบองค์ประกอบ
ในที่สุดใช้วิธีการขยายเพื่อให้ได้มรดกหลายครั้ง
Augment (ผู้แต่ง, Mixin); VAR Author = ผู้แต่งใหม่ ('JS', ['JavaScript Design Patterns']); การแจ้งเตือน (ผู้เขียน serialize ());นี่คือชั้นเรียนของผู้แต่ง ชั้นเรียนนี้สืบทอดมาจากชั้นเรียนหลักของบุคคลและยังมีวิธีการและคุณสมบัติของคลาสเมแทบอลิซึม หากคุณต้องการคุณสามารถกำหนดคลาสเมแทบอลิซึมเพื่อขยายชั้นเรียน นอกจากนี้ยังสามารถสืบทอดคุณสมบัติและวิธีการของคลาสเมแทบอลิซึมอื่น ๆ ที่คุณกำหนดไว้เพื่อให้มีการรับมรดกหลายครั้ง ในที่สุดผลการดำเนินงานของวิธีการอนุกรมของผู้เขียนมีดังนี้:
คุณจะพบว่าคลาสนี้มีทั้งคุณสมบัติและวิธีการของคลาสบุคคลคลาสผู้แต่งและคลาส Mixin คุณสมบัติและวิธีการของบุคคลและ mixin ล้วนได้มาจาก "มรดก" ในความเป็นจริงมันตระหนักถึงการสืบทอดหลายครั้ง