หากคุณไม่สามารถเข้าใจความรู้ได้ในเวลานั้นคุณสามารถปล่อยให้มันไปได้ตลอดเวลาและปล่อยให้มันไปสู่อนาคตและบางทีคุณอาจเข้าใจได้
ไม่กี่เดือนที่ผ่านมาฉันถือ "JavaScript Advanced Programming (ฉบับที่สาม)" และหลังจากเคี้ยวในการสร้างวัตถุฉันเริ่มเคี้ยวมรดก อย่างไรก็ตามหลังจากเคี้ยวโซ่ต้นแบบฉันไม่สามารถยืนได้อีกต่อไปและจิตใจของฉันก็ยุ่งมากขึ้นเรื่อย ๆ ดังนั้นฉันจึงโยนมันทิ้งไปและมองต่อไป ตอนนี้ฉันได้ใช้วันหยุดฤดูร้อนนี้เพื่อทำความเข้าใจกับมรดกนี้ฉันจะจัดเรียงโน้ตของฉัน
การผูกมัดต้นแบบ
มาอ่านบทความก่อน ผู้เขียนบทความนั้นดีมากและมีภาพความละเอียดสูง ฮ่าๆ…
ลิงค์: [บันทึกการศึกษา] ดูโซ่ต้นแบบ JS จากมุมมองเล็ก ๆ
ไม่กี่คำจากข้อความต้นฉบับ
กำหนดความสัมพันธ์ระหว่างต้นแบบและอินสแตนซ์
มีสองวิธีในการตรวจจับความสัมพันธ์ระหว่างต้นแบบและอินสแตนซ์:
อินสแตนซ์ของ: กำหนดว่าวัตถุนั้นเป็นอินสแตนซ์ของวัตถุอื่น
กลไกการคำนวณภายในของอินสแตนซ์ของมีดังนี้:
functionInstance_of (l, r) {// l หมายถึงนิพจน์ด้านซ้าย r หมายถึงนิพจน์ที่ถูกต้อง varo = r.prototype; // ใช้ต้นแบบการแสดงผลของ r l = l .__ proto__; // ใช้ต้นแบบโดยนัยของ L ในขณะที่ (จริง) {ถ้า (l === null) returnFalse; ถ้า (o === l) // ที่นี่จุด: เมื่อ o เท่ากับ l เท่ากับ l อย่างเคร่งครัดให้ส่งคืน truereturntrue; l = l .__ proto__; -รหัสข้างต้นถูกตัดตอนมาจาก: การวิเคราะห์เชิงลึกของตัวดำเนินการอินสแตนซ์ JavaScript
isprototypeof (): ทดสอบว่าวัตถุมีอยู่ในห่วงโซ่ต้นแบบของวัตถุอื่น
โปรดดูความแตกต่างระหว่างสองวิธีนี้: JavaScript isprototypeof vs อินสแตนซ์ของการใช้งาน
ใช้เฉพาะห่วงโซ่ต้นแบบเพื่อให้ได้มรดก
ข้อเสีย: 1. แอตทริบิวต์ต้นแบบที่อ้างถึงค่าประเภทจะถูกแชร์โดยอินสแตนซ์; 2. เมื่อสร้างอินสแตนซ์ของชนิดย่อยพารามิเตอร์ไม่สามารถส่งผ่านไปยังตัวสร้าง Supertype
functionfather () {this.name = "พ่อ"; this.friends = ['aaa', 'bbb'];} functionson () {} son.prototype = newfather (); son.prototype.constructor = son; vars1 = newSon (); fatherconsole.log (s2.name); // fathers1.name = "son"; console.log (s1.name); // sonconsole.log (s2.name); // fatherconsole.log (s1.friends); // ["aaa", "bbb" "bbb"] s1.friends.push ('ccc', 'ddd'); console.log (s1.friends); // ["aaa", "bbb", "ccc", "ddd"] console.log (s2.friends);ใช้ตัวสร้างเท่านั้นเพื่อให้ได้มรดก
วิธีการใช้งาน: เรียกตัวสร้าง Supertype ภายในตัวสร้างชนิดย่อย (ใช้วิธีการใช้งาน () และการโทร ())
ข้อดี: แก้ปัญหาการอ้างอิงแอตทริบิวต์ประเภทในต้นแบบและคลาสย่อยสามารถส่งผ่านพารามิเตอร์ไปยัง superclasses
ข้อเสีย: อินสแตนซ์ subclass ไม่สามารถเข้าถึงวิธีการที่กำหนดไว้ในต้นแบบ Parent Class (SuperClass) ดังนั้นจึงไม่มีวิธีที่จะพูดคุยเกี่ยวกับการใช้ฟังก์ชั่นซ้ำ
functionfather (ชื่อ, เพื่อน) {this.name = name; this.friends = friends;} father.prototype.getName = function () {returnthis.name;}; functionson (ชื่อ) {// หมายเหตุ: father.call (นี่, ชื่อ, ['aaa', 'bbb']); this.age = 22;} vars1 = newson ('son1'); vars2 = newson ('son2'); console.log (s1.name); // son1console.log (s2.name); son2s1.friends.push ('ccc', 'ddd'); console.log (s1.friends); // ["aaa", "bbb", "ccc", "ddd"] console.log (s2.friends); // ["aaa", "bbb" // typeError: s1.getName ไม่ใช่ functions2.getName (); // typeError: s2.getName ไม่ใช่ฟังก์ชั่นมรดกแบบผสมผสาน
วิธีการใช้งาน: ใช้ห่วงโซ่ต้นแบบเพื่อใช้การสืบทอดคุณสมบัติและวิธีการต้นแบบและใช้ตัวสร้างเพื่อใช้การสืบทอดคุณสมบัติอินสแตนซ์
functionfather (ชื่อ, เพื่อน) {this.name = name; this.friends = friends;} father.prototype.money = "100k $"; พ่อ. prototype.getName = function () {console.log father.call (นี่, ชื่อ, ['aaa', 'bbb']); this.age = Age;} // สืบทอดคุณสมบัติและวิธีการใน Son.prototype = newFather (); consoly.log.constructor = son.prototype.prototy = Newson ('son1', 12); s1.friends.push ('ccc'); console.log (s1.friends); // ["aaa", "bbb", "ccc"] console.log (s1.money); // 100k $ s1.getname (); // son1s1.getage (); // 12vars2 = Newson ('Son2', 24); console.log (s2.friends); // ["aaa", "bbb"] console.log (s2.money); // 100k $ s2.getName (); // son2s2.getage (); // 24การสืบทอดการรวมกันช่วยหลีกเลี่ยงข้อบกพร่องของฝ่ายเดียวโดยใช้เครือข่ายต้นแบบหรือตัวสร้างเพื่อใช้การสืบทอดรวมข้อดีของพวกเขาและกลายเป็นแบบจำลองการสืบทอดที่ใช้กันมากที่สุดใน JavaScript แต่ก็มีข้อบกพร่องและข้อบกพร่องของการสืบทอดการรวมกันจะถูกกล่าวถึงในภายหลัง
มรดกต้นแบบ
แนวคิดการใช้งาน: ใช้ต้นแบบเพื่อสร้างวัตถุใหม่ตามวัตถุที่มีอยู่โดยไม่ต้องสร้างประเภทที่กำหนดเองเนื่องจากสิ่งนี้
เพื่อให้บรรลุเป้าหมายนี้มีการแนะนำฟังก์ชั่นต่อไปนี้ (OBJ)
functionObj (o) {functionf () {} f.prototype = o; returnNewf ();} varperson1 = {ชื่อ: "percy", เพื่อน: ['aaa', 'bbb']}; varperson2 = obj (person1); person2.name = "zyj"; person2.friends.push ('ccc'); console.log (person1.name); // percyconsole.log (person2.name); // zyjconsole.log (person1.friends); "CCC"] ECMASCRIPT 5 ทำให้การสืบทอดการสืบทอดต้นแบบเป็นปกติโดยการเพิ่มเมธอด object.create () ในกรณีของการส่งผ่านในพารามิเตอร์วิธีการสร้าง () และ obj () มีพฤติกรรมเหมือนกัน varperson1 = {ชื่อ: "เพอร์ซี่", เพื่อน: ['aaa', 'bbb']}; varperson2 = object.create (person1); person2.name = "zyj"; person2.friends.push ('ccc'); console.log (person1.name); zyjconsole.log (person1.friends); // ["aaa", "bbb", "ccc"] console.log (person2.friends); // ["aaa", "bbb", "ccc"]การสืบทอดนี้สามารถเลือกได้เมื่อไม่จำเป็นต้องระดมคอนสตรัคเตอร์เพื่อสร้างมัน แต่เพียงต้องการให้วัตถุหนึ่งตัวยังคงคล้ายกับอีกวัตถุหนึ่ง
มรดกปรสิต
การสืบทอดปรสิตเป็นความคิดที่เกี่ยวข้องอย่างใกล้ชิดกับการสืบทอดต้นแบบ
แนวคิดการใช้งาน: สร้างฟังก์ชั่นที่ใช้ในการห่อหุ้มกระบวนการสืบทอดซึ่งจะช่วยเพิ่มวัตถุภายในไม่ทางใดก็ทางหนึ่งและในที่สุดก็ส่งคืนวัตถุ
functionObj (o) {functionf () {} f.prototype = o; returnNewf ();} functionCreatePerson (ต้นฉบับ) {// encapsulate กระบวนการสืบทอด varclone = obj (ต้นฉบับ); }; returnClone; // return Object} varperson = {ชื่อ: "percy"}; varperson1 = createperson (บุคคล); console.log (person1.name); // percyperson1.showsomething (); // สวัสดีโลก!การสืบทอดการรวมกันของกาฝาก
ก่อนอื่นมาพูดถึงข้อบกพร่องของมรดกชุดก่อนหน้าของเรา ปัญหาที่ใหญ่ที่สุดของการสืบทอดการรวมกันคือไม่ว่าสถานการณ์จะเป็นอย่างไรตัวสร้างของคลาสแม่จะถูกเรียกสองครั้ง: หนึ่งคือเมื่อสร้างต้นแบบของคลาสย่อยและอีกระดับคือเมื่อเรียกคอนสตรัคเตอร์คลาสย่อยตัวสร้างของคลาสแม่จะเรียกว่าภายในคอนสตรัคเตอร์ย่อย
functionfather (ชื่อ, เพื่อน) {this.name = name; this.friends = friends;} father.prototype.money = "100k $"; พ่อ. prototype.getName = function () {console.log father.call (นี่, ชื่อ, ['aaa', 'bbb']); // การเรียกครั้งที่สองไปยังพ่อ () เรียกจริงว่า this.age = age;} // สืบทอดคุณสมบัติและวิธีการในการเรียนชั้นเรียนการโทรครั้งแรกทำให้ต้นแบบของคลาสย่อยเป็นอินสแตนซ์ของคลาสแม่เพื่อให้ต้นแบบของคลาสย่อยได้รับแอตทริบิวต์อินสแตนซ์ของคลาสแม่ การโทรครั้งที่สองจะทำให้แอตทริบิวต์อินสแตนซ์ของคลาสย่อยเพื่อรับแอตทริบิวต์อินสแตนซ์ของคลาสแม่ และแอตทริบิวต์อินสแตนซ์ของคลาสย่อยจะบล็อกแอตทริบิวต์ที่ทำซ้ำกับต้นแบบ subclass โดยค่าเริ่มต้น ดังนั้นหลังจากการโทรทั้งสองนี้แอตทริบิวต์ที่ไม่จำเป็นจะปรากฏในต้นแบบ subclass ดังนั้นจึงแนะนำการสืบทอดการรวมกันของปรสิตเพื่อแก้ปัญหานี้
แนวคิดเบื้องหลังการสืบทอดการรวมกันของกาฝากคือ: ไม่จำเป็นต้องเรียกตัวสร้างคลาสแม่เพื่อระบุต้นแบบของคลาสย่อย สิ่งที่เราต้องการคือสำเนาของต้นแบบคลาสแม่
โดยพื้นฐานแล้วมันคือการใช้การสืบทอดปรสิตเพื่อสืบทอดต้นแบบของคลาสหลักแล้วกลับผลลัพธ์ไปยังต้นแบบของชั้นเด็ก
functionObj (o) {functionf () {} f.prototype = o; returnNewf ();} functionInherItPrototype (ลูกชาย, พ่อ) {varprototype = obj (พ่อ // ปรับปรุง Object Son.prototype = Prototype; // return object} functionFather (ชื่อ, เพื่อน) {this.name = name; this.friends = friends;} father.prototype.money = "100k $"; พ่อ. prototype.getName = function () {console.log father.call (นี่, ชื่อ, ['aaa', 'bbb']); this.age = age;} // สืบทอดคุณสมบัติและวิธีการในต้นแบบคลาสแม่ที่สืบทอดมรดก (ลูกชาย, พ่อ); son.prototype.getage = function () {console.log (this.age);}; vars1 = newson (son1 ', 12); ["AAA", "BBB", "CCC"] Console.log (S1.Money); // 100K $ S1.GetName (); // son1s1.getage (); // 12vars2 = Newson ('Son2', 24); console.log (s2.friends); // ["aaa", "bbb"] console.log (s2.money); // 100k $ s2.getName (); // son2s2.getage (); // 24ข้อดี: สร้างต้นแบบ subclass หลีกเลี่ยงการสืบทอดคุณสมบัติอินสแตนซ์ที่ไม่จำเป็นในคลาสหลัก
โดยทั่วไปนักพัฒนาเชื่อว่าการสืบทอดการสืบทอดของ parasitic combinatorial เป็นวิธีการสืบทอดในอุดมคติที่สุดบนพื้นฐานของการสืบทอดประเภท
ในที่สุด
ในที่สุดฉันขอแนะนำสองบทความที่ยากมาก
JavaScript วิธีการสืบทอดการสืบทอดต้นแบบใช้งานได้จริง
แผนภาพการสืบทอดมรดกคลาสสิกของ JavaScript (จำเป็นต้องข้ามผนัง)
ถ่ายรูปอย่างหนักจากบทความที่สอง:
หลังจากอ่านมันฉันเข้าใจห่วงโซ่ต้นแบบในไม่กี่วินาที มีอะไรบ้าง?
ข้างต้นคือการรวบรวมข้อมูลที่สืบทอดโดย JavaScript เราจะยังคงเพิ่มข้อมูลที่เกี่ยวข้องในอนาคต ขอบคุณสำหรับการสนับสนุนเว็บไซต์นี้!