แนวคิดของการสืบทอด JS
วิธีการสืบทอดสองวิธีต่อไปนี้ที่ใช้กันทั่วไปใน JS:
การสืบทอดโซ่ต้นแบบ (การสืบทอดระหว่างวัตถุ)
มรดกแบบคลาสสิก (การสืบทอดระหว่างตัวสร้าง)
เนื่องจาก JS ไม่ได้เป็นภาษาที่มุ่งเน้นวัตถุอย่างแท้จริงเช่น Java JS จึงเป็นอิงตามวัตถุและไม่มีแนวคิดของชั้นเรียน ดังนั้นหากคุณต้องการใช้การสืบทอดคุณสามารถใช้กลไกต้นแบบต้นแบบของ JS หรือใช้วิธีการใช้และการโทรเพื่อนำไปใช้
ในภาษาที่มุ่งเน้นวัตถุเราใช้คลาสเพื่อสร้างวัตถุที่กำหนดเอง อย่างไรก็ตามทุกอย่างใน JS เป็นวัตถุดังนั้นวิธีใดที่สามารถใช้ในการสร้างวัตถุที่กำหนดเองได้? สิ่งนี้ต้องใช้ต้นแบบ JS:
เราสามารถถือว่าต้นแบบเป็นเทมเพลต วัตถุที่กำหนดเองที่สร้างขึ้นใหม่เป็นสำเนาของเทมเพลตนี้ (ต้นแบบ) (จริง ๆ แล้วไม่ใช่สำเนา แต่เป็นลิงค์ แต่ลิงก์ประเภทนี้มองไม่เห็นมีตัวชี้ __proto__ ที่มองไม่เห็นภายในวัตถุอินสแตนซ์ใหม่ชี้ไปที่วัตถุต้นแบบ)
JS สามารถจำลองและใช้งานฟังก์ชั่นของคลาสผ่านตัวสร้างและต้นแบบ นอกจากนี้การใช้งานการสืบทอดประเภท JS นั้นทำได้โดยการพึ่งพาเครือข่ายต้นแบบ
มรดกต้นแบบและการสืบทอดคลาส
มรดกแบบคลาสสิกคือการเรียกของตัวสร้าง Supertype ภายในตัวสร้างชนิดย่อย
การสืบทอดคลาสที่เข้มงวดนั้นไม่ได้เป็นเรื่องธรรมดาและโดยทั่วไปจะใช้ร่วมกัน:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น super () {
this.colors = ["สีแดง", "blue"];
-
ฟังก์ชันย่อย () {
super.call (นี่);
-
การสืบทอดต้นแบบคือการสร้างวัตถุใหม่ด้วยความช่วยเหลือของวัตถุที่มีอยู่และชี้ต้นแบบของคลาสย่อยไปยังคลาสแม่ซึ่งเทียบเท่ากับการเพิ่มห่วงโซ่ต้นแบบของคลาสแม่
มรดกลูกโซ่ต้นแบบ
เพื่อให้ชั้นเด็กได้รับมรดกคุณสมบัติของคลาสแม่ (รวมถึงวิธีการ) ตัวสร้างเป็นสิ่งจำเป็นในการกำหนด จากนั้นกำหนดอินสแตนซ์ใหม่ของคลาสหลักให้กับต้นแบบของตัวสร้าง รหัสมีดังนี้:
การคัดลอกรหัสมีดังนี้:
<script>
ฟังก์ชัน parent () {
this.name = 'Mike';
-
ฟังก์ชั่นเด็ก () {
this.age = 12;
-
child.prototype = parent ใหม่ (); // เด็กสืบทอดแม่และสร้างโซ่ผ่านต้นแบบ
การทดสอบ var = เด็กใหม่ ();
การแจ้งเตือน (test.age);
Alert (test.name); // รับแอตทริบิวต์ที่สืบทอดมา
// ดำเนินการต่อเพื่อสืบทอดห่วงโซ่ต้นแบบ
ฟังก์ชั่นพี่ชาย () {// บราเดอร์สร้าง
this.weight = 60;
-
brother.prototype = เด็กใหม่ (); // ดำเนินการต่อไปเพื่อการสืบทอดโซ่ต้นแบบ
var brother = พี่ชายใหม่ ();
Alert (brother.name); // สืบทอดพ่อแม่และลูกไมค์ปรากฏขึ้น
Alert (brother.age); // pop 12
</script>
การสืบทอดโซ่ต้นแบบข้างต้นยังคงหายไปหนึ่งลิงก์นั่นคือวัตถุและตัวสร้างทั้งหมดได้รับการสืบทอดมาจากวัตถุ การสืบทอดวัตถุจะเสร็จสมบูรณ์โดยอัตโนมัติและไม่จำเป็นต้องมีการสืบทอดด้วยตนเองด้วยตนเอง แล้วความสัมพันธ์รองของพวกเขาคืออะไร?
กำหนดความสัมพันธ์ระหว่างต้นแบบและอินสแตนซ์
มีสองวิธีในการกำหนดความสัมพันธ์ระหว่างต้นแบบและอินสแตนซ์ วิธีการอินสแตนซ์ของวิธีการและ isprototypeof ():
การคัดลอกรหัสมีดังนี้:
การแจ้งเตือน (วัตถุอินสแตนซ์ของพี่ชาย) // จริง
การแจ้งเตือน (การทดสอบอินสแตนซ์ของพี่ชาย); // เท็จการทดสอบเป็นซูเปอร์คลาสของพี่ชาย
การแจ้งเตือน (ตัวอย่างพี่ชายของเด็ก); // true
การแจ้งเตือน (ตัวอย่างพี่ชายของพ่อแม่); // true
ตราบใดที่มันเป็นต้นแบบที่ปรากฏในห่วงโซ่ต้นแบบก็สามารถกล่าวได้ว่าเป็นต้นแบบของอินสแตนซ์ที่ได้มาจากห่วงโซ่ต้นแบบ ดังนั้นวิธี isprototypeof () จะกลับมาเป็นจริง
ใน JS ฟังก์ชั่นที่สืบทอดมานั้นเรียกว่า supertype (คลาสหลักคลาสฐานและ) และฟังก์ชั่นที่สืบทอดมาเรียกว่าชนิดย่อย (คลาสย่อย, คลาสที่ได้รับ) การใช้การสืบทอดต้นแบบส่วนใหญ่เกี่ยวข้องกับสองประเด็น:
ขั้นแรกการเขียนต้นแบบใหม่อย่างแท้จริงจะทำลายความสัมพันธ์ใช้ต้นแบบของประเภทการอ้างอิงและชนิดย่อยไม่สามารถส่งพารามิเตอร์ไปยัง Supertype ได้
Pseudo-Class แก้ปัญหาการแบ่งปันอ้างอิงและ supertypes ไม่สามารถผ่านข้อโต้แย้งได้ เราสามารถใช้เทคโนโลยี "ยืมตัวสร้าง"
ตัวยืมตัวสร้าง (มรดกแบบคลาสสิก)
การคัดลอกรหัสมีดังนี้:
<script>
ฟังก์ชั่นพาเรนต์ (อายุ) {
this.name = ['Mike', 'Jack', 'Smith'];
this.age = อายุ;
-
ฟังก์ชั่นเด็ก (อายุ) {
parent.call (นี้อายุ);
-
การทดสอบ var = เด็กใหม่ (21);
Alert (test.age); // 21
Alert (test.name); // Mike, Jack, Smith
test.name.push ('บิล');
Alert (test.name); // Mike, Jack, Smith, Bill
</script>
แม้ว่าตัวสร้างการยืมจะแก้ไขปัญหาทั้งสองในขณะนี้โดยไม่มีต้นแบบ แต่ก็ไม่มีวิธีที่จะนำมาใช้ใหม่ดังนั้นเราจึงต้องใช้รูปแบบตัวสร้างต้นแบบ + ยืมตัวสร้าง รูปแบบนี้เรียกว่ามรดกแบบผสมผสาน
มรดกแบบผสมผสาน
การคัดลอกรหัสมีดังนี้:
<script>
ฟังก์ชั่นพาเรนต์ (อายุ) {
this.name = ['Mike', 'Jack', 'Smith'];
this.age = อายุ;
-
parent.prototype.run = function () {
return this.name + 'เป็นทั้ง' + this.age;
-
ฟังก์ชั่นเด็ก (อายุ) {
parent.call (นี่, อายุ); // Object Impersonate และส่งพารามิเตอร์ไปยัง supertypes
-
child.prototype = parent ใหม่ (); // การสืบทอดโซ่ต้นแบบ
test var = เด็กใหม่ (21); // การเขียนแม่ใหม่ (21) ก็โอเค
Alert (test.run ()); // mike, jack, smith เป็นทั้ง 21
</script>
การสืบทอดการรวมกันเป็นวิธีการสืบทอดที่ใช้กันทั่วไป แนวคิดที่อยู่เบื้องหลังคือการใช้ห่วงโซ่ต้นแบบเพื่อใช้การสืบทอดคุณสมบัติและวิธีการต้นแบบและเพื่อใช้การสืบทอดคุณสมบัติอินสแตนซ์โดยการยืมตัวสร้าง ด้วยวิธีนี้ฟังก์ชั่นมัลติเพล็กซ์ทำได้โดยการกำหนดวิธีการบนต้นแบบและทำให้มั่นใจว่าแต่ละอินสแตนซ์มีคุณสมบัติของตัวเอง
การใช้การโทร (): เรียกวิธีการของวัตถุและแทนที่วัตถุปัจจุบันด้วยวัตถุอื่น
การคัดลอกรหัสมีดังนี้:
การโทร ([thisobj [, arg1 [, arg2 [, [, .argn]]]]])])
มรดกต้นแบบ
วิธีนี้ในการสืบทอดการสร้างวัตถุใหม่ตามวัตถุที่มีอยู่โดยไม่ต้องสร้างประเภทที่กำหนดเองเรียกว่าการสืบทอดต้นแบบ
การคัดลอกรหัสมีดังนี้:
<script>
ฟังก์ชั่น obj (o) {
ฟังก์ชั่น f () {}
f.prototype = o;
คืน F () ใหม่;
-
var box = {
ชื่อ: 'Trigkit4'
arr: ['พี่ชาย', 'น้องสาว', 'บาบา']
-
var b1 = obj (กล่อง);
การแจ้งเตือน (b1.name); // trigkit4
b1.name = 'Mike';
การแจ้งเตือน (b1.name); // Mike
การแจ้งเตือน (b1.arr); // พี่ชายน้องสาวบาบา
b1.arr.push ('ผู้ปกครอง');
การแจ้งเตือน (b1.arr); // พี่ชายน้องสาวบาบาพ่อแม่
var b2 = obj (กล่อง);
การแจ้งเตือน (b2.name); // trigkit4
Alert (b2.arr); // พี่ชายน้องสาวบาบาพ่อแม่
</script>
การสืบทอดต้นแบบแรกสร้างตัวสร้างชั่วคราวภายในฟังก์ชั่น OBJ () จากนั้นใช้วัตถุที่ผ่านเป็นต้นแบบของตัวสร้างและในที่สุดก็ส่งคืนอินสแตนซ์ใหม่ของประเภทชั่วคราวนี้
มรดกปรสิต
วิธีการสืบทอดนี้รวมโมเดลต้นแบบ + โรงงานเข้ากับวัตถุประสงค์ของกระบวนการสร้างการห่อหุ้ม
การคัดลอกรหัสมีดังนี้:
<script>
ฟังก์ชั่นสร้าง (o) {
var f = obj (o);
f.run = function () {
ส่งคืน this.arr; // ในทำนองเดียวกันการอ้างอิงจะถูกแบ่งปัน
-
กลับ f;
-
</script>
ปัญหาเล็ก ๆ น้อย ๆ เกี่ยวกับการสืบทอดการรวมกัน
การสืบทอดการรวมกันเป็นโหมดการสืบทอดที่ใช้กันมากที่สุดใน JS แต่ supertype ของการสืบทอดการรวมกันจะถูกเรียกสองครั้งในระหว่างการใช้งาน; ครั้งหนึ่งคือเมื่อสร้างชนิดย่อยและอื่น ๆ อยู่ในตัวสร้างชนิดย่อย
การคัดลอกรหัสมีดังนี้:
<script>
ฟังก์ชันพาเรนต์ (ชื่อ) {
this.name = ชื่อ;
this.arr = ['พี่ชาย', 'น้องสาว', 'พ่อแม่'];
-
parent.prototype.run = function () {
ส่งคืนสิ่งนี้ชื่อ;
-
ฟังก์ชั่นเด็ก (ชื่ออายุ) {
parent.call (นี่, อายุ); // การโทรครั้งที่สอง
this.age = อายุ;
-
child.prototype = parent ใหม่ (); // การโทรครั้งแรก
</script>
รหัสข้างต้นคือการสืบทอดการรวมกันก่อนหน้านี้ดังนั้นการสืบทอดการรวมกันของปรสิตจะช่วยแก้ปัญหาของการโทรสองครั้ง
การสืบทอดการรวมกันของกาฝาก
การคัดลอกรหัสมีดังนี้:
<script>
ฟังก์ชั่น obj (o) {
ฟังก์ชั่น f () {}
f.prototype = o;
คืน F () ใหม่;
-
ฟังก์ชั่นสร้าง (parent, test) {
var f = obj (parent.prototype); // สร้างวัตถุ
f.Constructor = test; // ปรับปรุงวัตถุ
-
ฟังก์ชันพาเรนต์ (ชื่อ) {
this.name = ชื่อ;
this.arr = ['พี่ชาย', 'น้องสาว', 'พ่อแม่'];
-
parent.prototype.run = function () {
ส่งคืนสิ่งนี้ชื่อ;
-
ฟังก์ชั่นเด็ก (ชื่ออายุ) {
parent.call (ชื่อนี้);
this.age = อายุ;
-
มรดกได้รับ (ผู้ปกครอง, เด็ก); // การสืบทอดได้รับการรับรู้ผ่านที่นี่
test var = เด็กใหม่ ('trigkit4', 21);
test.arr.push ('หลานชาย');
การแจ้งเตือน (test.arr); //
Alert (test.run ()); // เฉพาะวิธีการแบ่งปัน
var test2 = เด็กใหม่ ('jack', 22);
การแจ้งเตือน (test2.arr); // แก้ปัญหาการอ้างอิง
</script>
โทรและสมัคร
ฟังก์ชั่นส่วนกลางใช้และการโทรสามารถใช้เพื่อเปลี่ยนการชี้ของสิ่งนี้ในฟังก์ชั่นดังต่อไปนี้:
การคัดลอกรหัสมีดังนี้:
// กำหนดฟังก์ชั่นทั่วโลก
ฟังก์ชั่น foo () {
console.log (this.fruit);
-
// กำหนดตัวแปรทั่วโลก
var fruit = "Apple";
// ปรับแต่งวัตถุ
var pack = {
ผลไม้: "สีส้ม"
-
// เทียบเท่ากับ window.foo ();
foo.apply (หน้าต่าง); // "Apple" ซึ่งเท่ากับหน้าต่าง
// นี่ === แพ็คใน foo
foo.apply (แพ็ค); // "ส้ม"