คำอธิบายของการสืบทอด JavaScript ได้ตกลงกัน แต่มันล่าช้า โดยไม่ต้องกังวลใจต่อไปเพียงแค่ไปถึงจุด
เนื่องจากคุณต้องการที่จะเข้าใจการสืบทอดมันพิสูจน์ได้ว่าคุณมีความเข้าใจบางอย่างเกี่ยวกับวัตถุ JavaScript ที่มุ่งเน้น หากคุณไม่เข้าใจอะไรเลยคุณสามารถอ้างถึงคำอธิบายพื้นฐานของ JS ที่มุ่งเน้นวัตถุ, โหมดโรงงาน, โหมดตัวสร้าง, โหมดต้นแบบ, โหมดผสม, โหมดต้นแบบไดนามิก "ต่อไปให้พูดคุยเกี่ยวกับการสืบทอดของ JavaScript โดยทั่วไปผ่านวิธีการเหล่านั้น
ห่วงโซ่ต้นแบบ
วิธีที่ง่ายที่สุดในการใช้มรดกใน JavaScript คือการใช้ห่วงโซ่ต้นแบบและชี้ต้นแบบของประเภทเด็กไปที่อินสแตนซ์ของประเภทพาเรนต์นั่นคือ "subtype.prototype = ประเภทแม่ใหม่ ();" วิธีการใช้งานมีดังนี้:
// สร้างฟังก์ชั่นคอนสตรัคเตอร์ supertype () {this.name = ['wuyuchang', 'jack', 'tim']; this.property = true;} // เพิ่มเมธอด supertype.prototype.getSuerperValue = function () {return this.property;} // สร้างฟังก์ชั่น substructor () {this.test = [h1 ',' h2 ',' h3 ',', 'h4']; this.subProperty = false;} // ขั้นตอนสำคัญในการใช้งานมรดกต้นแบบของชนิดย่อยชี้ไปที่อินสแตนซ์ของชนิดย่อยประเภทแม่พันธุ์. prototype = ใหม่ supertype (); // เพิ่มวิธีการในประเภทเด็กที่นี่ จะต้องเป็นหลังจากการสืบทอดถูกนำไปใช้มิฉะนั้นตัวชี้จะถูกชี้ไปที่อินสแตนซ์ของประเภทหลักและวิธีการว่างเปล่า subtype.prototype.getSubValue = function () {return this.subproperty;}/* ต่อไปนี้เป็นตัวอย่างรหัสทดสอบ*/var instance1 = ใหม่ชนิดย่อย (); instance1.name.push ('wyc'); instance1.test.push ('h5'); // truealert (instance1.getSubValue ()); // falsealert (instance1.name); // Wuyuchang, Jack, Tim, Wycalert (อินสแตนซ์ 1.test); // h1, h2, h3, h4, h5var instance2 = new type (); Alert (instance2.name); // Wuyuchang, Jack, Tim, Wycalert (อินสแตนซ์ 2.test); // h1, h2, h3, h4คุณจะเห็นว่ารหัสข้างต้นเป็นมรดกอย่างง่ายที่นำมาใช้ผ่านห่วงโซ่ต้นแบบ แต่ยังมีปัญหาบางอย่างในตัวอย่างรหัสทดสอบ ฉันเชื่อว่าหลังจากอ่านโพสต์บล็อกของฉัน "คำอธิบายพื้นฐานของ JS ที่มุ่งเน้นวัตถุ, โหมดโรงงาน, โหมดตัวสร้าง, โหมดต้นแบบ, โหมดผสม, โหมดต้นแบบไดนามิก" ฉันต้องรู้ ว่าปัญหาแรกของรหัสห่วงโซ่ แอตทริบิวต์ที่อ้างอิงค่าประเภทจะถูกแชร์โดยทุกกรณี instance1.name.push ('wyc'); จากรหัสข้างต้นสามารถพิสูจน์การมีอยู่ของปัญหานี้ ปัญหาที่สองของห่วงโซ่ต้นแบบคือ เมื่อสร้างอินสแตนซ์ของชนิดย่อยพารามิเตอร์ไม่สามารถส่งผ่านไปยังตัวสร้าง Supertype ดังนั้นในการพัฒนาจริงเราไม่ค่อยใช้เครือข่ายต้นแบบเพียงอย่างเดียว
ยืมตัวสร้าง
เพื่อแก้ปัญหาสองข้อในห่วงโซ่ต้นแบบนักพัฒนาเริ่มใช้เทคนิคที่เรียกว่าตัวสร้างการยืมเพื่อแก้ปัญหาในห่วงโซ่ต้นแบบ แนวคิดการใช้งานของเทคโนโลยีนี้ก็ค่อนข้างง่าย คุณจะต้องเรียกตัวสร้างของประเภทหลักภายในตัวสร้างของชนิดย่อย อย่าลืมว่าฟังก์ชั่นเป็นเพียงวัตถุที่เรียกใช้รหัสในสภาพแวดล้อมที่เฉพาะเจาะจงดังนั้น ตัวสร้างสามารถดำเนินการผ่านวิธีการสมัคร () หรือการโทร () รหัสมีดังนี้:
// สร้างฟังก์ชั่นคอนสตรัคเตอร์ superType (ชื่อ) {this.name = name; this.color = ['Pink', 'Yellow']; this.property = true; this.testfun = function () {Alert ('http://tools.vevb.com/'); }} // เพิ่มเมธอด superType.prototype.getSuerperValue = function () {return this.property;} // สร้างฟังก์ชันคอนสตรัคเตอร์ชนิดย่อย (ชื่อ) {supertype.call (ชื่อนี้); this.test = ['H1', 'H2', 'H3', 'H4']; this.subProperty = false;} // เพิ่มวิธีการลงในชนิดย่อยที่นี่ อย่าลืมใช้การสืบทอดมิฉะนั้นตัวชี้จะชี้ไปที่อินสแตนซ์ของประเภทหลักและวิธีการที่ว่างเปล่าชนิดย่อย prototype.getSubValue = function () {return this.subproperty;}/* ต่อไปนี้เป็นตัวอย่างรหัสทดสอบ*/var instance1 = ใหม่ชนิดย่อย ( 'nick']); instance1.name.push ('hello'); instance1.test.push ('h5'); instance1.color.push ('blue'); instance1.testfun (); // http://tools.vevb.com/alert(instance1.name); // Wuyuchang, Jack, Nick, Hello // Alert (instance1.getSuerperValue ()); // การแจ้งเตือนข้อผิดพลาด (อินสแตนซ์ 1.test); // h1, h2, h3, h4, h5 การแจ้งเตือน (อินสแตนซ์ 1.getsubvalue ()); // การแจ้งเตือนเท็จ (อินสแตนซ์ 1.Color); // สีชมพู, เหลือง, BlueVar Instance2 = ใหม่ชนิดย่อย ('WYC'); Instance2.testfun (); // http://tools.vevb.com/alert(instance2.name); // wyc // alert (instance2.getSuerperValue ()); // การแจ้งเตือนข้อผิดพลาด (อินสแตนซ์ 2.test); // h1, h2, h3, h4alert (instance2.getsubvalue ()); // FalseAlert (อินสแตนซ์ 2.Color); // สีชมพูสีเหลืองคุณจะเห็นได้ว่าในรหัสข้างต้นตัวสร้างของชนิดย่อยชนิดย่อยในรหัสข้างต้นการสืบทอดของแอตทริบิวต์จะรับรู้โดยการเรียกประเภทพาเรนต์ "supertype.call (ชื่อนี้);" นอกจากนี้คุณยังสามารถส่งผ่านพารามิเตอร์ไปยังประเภทพาเรนต์เมื่อมีการสร้างชนิดย่อย แต่ปัญหาใหม่กำลังจะมาถึง คุณจะเห็นว่าฉันกำหนดวิธีการในตัวสร้างประเภทหลัก: testfun และวิธีการในต้นแบบของประเภทหลัก: getSupervalue อย่างไรก็ตาม หลังจากอินสแตนซ์ชนิดย่อยมันยังคงเป็นไปไม่ได้ที่จะเรียกวิธีการ getSupervalue ที่กำหนดไว้ในต้นแบบของประเภทพาเรนต์ และสามารถเรียกใช้วิธีการของตัวสร้างในประเภทหลัก: testfun นี่เป็นเพียงการใช้เฉพาะโหมดตัวสร้างในการสร้างวัตถุเพื่อให้ฟังก์ชั่นไม่มีความสามารถในการนำกลับมาใช้ใหม่ได้ เมื่อคำนึงถึงปัญหาเหล่านี้เทคนิคการยืมตัวสร้างไม่ค่อยได้ใช้เพียงอย่างเดียว
การสืบทอดการรวมกัน (chain prototype + ยืมตัวสร้าง)
ตามชื่อที่แนะนำการสืบทอดการรวมกันเป็นรูปแบบที่ประกอบด้วยข้อดีของการรวมการใช้โซ่ต้นแบบและตัวสร้างการยืม การใช้งานก็ง่ายมาก เนื่องจากเป็นการรวมกันแน่นอนว่ามันรวมข้อดีของทั้งสองฝ่าย ได้แก่ วิธีการสืบทอดโซ่ต้นแบบและตัวสร้างสืบทอดคุณลักษณะ รหัสเฉพาะถูกนำไปใช้ดังนี้:
// สร้างฟังก์ชั่นคอนสตรัคเตอร์ superType (ชื่อ) {this.name = name; this.color = ['Pink', 'Yellow']; this.property = true; this.testfun = function () {Alert ('http://tools.vevb.com/'); }} // เพิ่มเมธอด superType.prototype.getSuerperValue = function () {return this.property;} // สร้างฟังก์ชันคอนสตรัคเตอร์ชนิดย่อย (ชื่อ) {supertype.call (ชื่อนี้); this.test = ['H1', 'H2', 'H3', 'H4']; this.subProperty = false;} subtype.prototype = new supertype (); // เพิ่มวิธีการลงในชนิดย่อยที่นี่ มันจะต้องเป็นหลังจากการสืบทอดการสืบทอดมิฉะนั้นตัวชี้จะถูกชี้ไปที่อินสแตนซ์ของประเภทพาเรนต์และวิธีการที่ว่างเปล่าชนิดย่อย prototype.getSubValue = function () {ส่งคืนสิ่งนี้ subproperty;}/* ต่อไปนี้เป็นตัวอย่างรหัสทดสอบ*/var Instance1 = ใหม่ย่อย 'nick']); instance1.name.push ('hello'); instance1.test.push ('h5'); instance1.color.push ('blue'); instance1.testfun (); // http://tools.vevb.com/alert(instance1.name); // Wuyuchang, Jack, Nick, Helloalert (instance1.getSuerperValue ()); // truealert (อินสแตนซ์ 1.test); // h1, h2, h3, h4, h5 การแจ้งเตือน (อินสแตนซ์ 1.getsubvalue ()); // การแจ้งเตือนเท็จ (อินสแตนซ์ 1.Color); // สีชมพู, เหลือง, BlueVar Instance2 = ใหม่ชนิดย่อย ('WYC'); Instance2.testfun (); // http://tools.vevb.com/alert(instance2.name); // WYC Alert (instance2.getSuerperValue ()); // truealert (อินสแตนซ์ 2.test); // h1, h2, h3, h4alert (instance2.getsubvalue ()); // FalseAlert (อินสแตนซ์ 2.Color); // สีชมพูสีเหลืองรหัสข้างต้นสืบทอดคุณสมบัติของประเภทพาเรนต์ผ่าน supertype.call (ชื่อนี้); และสืบทอดวิธีการของประเภทพาเรนต์ผ่านชนิดย่อย prototype = new supertype (); รหัสข้างต้นช่วยแก้ปัญหาที่พบโดยห่วงโซ่ต้นแบบและตัวสร้างการยืมอย่างสะดวกและได้กลายเป็นวิธีที่ใช้กันมากที่สุดในการสืบทอดอินสแตนซ์ในจาวาสคริปต์ อย่างไรก็ตามโหมดผสมไม่ได้ไม่มีข้อบกพร่อง จะเห็นได้ว่าในรหัสข้างต้นคุณลักษณะของประเภทหลักได้รับการสืบทอดจริง ๆ เมื่อสืบทอดวิธีการ อย่างไรก็ตามประเภทการอ้างอิงจะถูกแชร์ในเวลานี้ ดังนั้นตัวสร้างของประเภทหลักจึงเรียกว่าในตัวสร้างประเภทลูกหลังจากชนิดย่อยดังนั้นจึงสืบทอดคุณลักษณะของประเภทพาเรนต์เพื่อเขียนทับแอตทริบิวต์ที่สืบทอดมาในต้นแบบ เห็นได้ชัดว่าไม่จำเป็นต้องโทรหาคอนสตรัคเตอร์สองครั้ง แต่มีวิธีแก้ปัญหาหรือไม่? เมื่อแก้ปัญหานี้ก่อนอื่นให้ดูสองโหมดต่อไปนี้
มรดกต้นแบบ
วิธีการดำเนินการของการสืบทอดต้นแบบนั้นแตกต่างจากการสืบทอดทั่วไป การสืบทอดต้นแบบไม่ได้ใช้ตัวสร้างในความหมายที่เข้มงวด แต่แทนที่จะใช้ต้นแบบเพื่อสร้างวัตถุใหม่ตามวัตถุที่มีอยู่และไม่จำเป็นต้องสร้างประเภทที่กำหนดเองตามผลลัพธ์ รหัสเฉพาะมีดังนี้:
วัตถุฟังก์ชัน (o) {ฟังก์ชัน f () {} f.prototype = o; ส่งคืน f () ใหม่}ตัวอย่างรหัส:
/* การสืบทอดต้นแบบ*/ฟังก์ชันวัตถุ (o) {ฟังก์ชั่น f () {} f.prototype = o; ส่งคืน f () ใหม่} var person = {ชื่อ: 'wuyuchang', เพื่อน: ['wyc', 'nicholas', 'tim']} var otherperson = object (บุคคล); อีกคนหนึ่ง. name = 'greg'; Anotherperson.friends.push ('bob'); var otherperson2 = วัตถุ (บุคคล); อีกคนหนึ่ง 2.name = 'jack'; ounterperson2.friends.push ('Rose'); Alert (person.friends); // WYC, Nicholas, Tim, Bob, Roseมรดกปรสิต
/* การสืบทอดปรสิต*/ฟังก์ชั่น createAnother (ต้นฉบับ) {var clone = วัตถุ (ต้นฉบับ); clone.sayhi = function () {Alert ('Hi'); } return clone;}ตัวอย่างการใช้งาน:
/* การสืบทอดต้นแบบ*/ฟังก์ชันวัตถุ (o) {ฟังก์ชั่น f () {} f.prototype = o; ส่งคืน F () ใหม่} /* การสืบทอดปรสิต* /ฟังก์ชั่น createAnother (ต้นฉบับ) {var clone = วัตถุ (ต้นฉบับ); clone.sayhi = function () {Alert ('Hi'); } return clone;} var person = {ชื่อ: 'wuyuchang', เพื่อน: ['wyc', 'nicholas', 'rose']} var otherperson = createAnother (บุคคล); อีกคนหนึ่ง Sayhi ();การสืบทอดการรวมกันของกาฝาก
ฉันได้กล่าวถึงข้อเสียก่อนหน้านี้ของการใช้รูปแบบการรวมกันของการสืบทอดใน JavaScript ตอนนี้มาแก้ข้อบกพร่องของมันกันเถอะ แนวคิดการใช้งานคือการสืบทอดคุณลักษณะสำหรับตัวสร้างและวิธีการสืบทอดแบบฟอร์มผสมของห่วงโซ่ต้นแบบไม่จำเป็นต้องสร้างอินสแตนซ์คอนสตรัคเตอร์ของประเภทพาเรนต์เมื่อสืบทอดวิธีการ รหัสมีดังนี้:
วัตถุฟังก์ชัน (o) {ฟังก์ชัน f () {} f.prototype = o; ส่งคืน F () ใหม่}/* การรวมกันของปรสิตการสืบทอด*/ฟังก์ชั่นสืบทอดมรดก (ชนิดย่อย, supertype) {var prototype = วัตถุ (supertype.prototype); Prototype.Constructor = ชนิดย่อย; subtype.prototype = prototype;}เมื่อใช้งานคุณจะต้องแทนที่บรรทัดของรหัส "subtype.prototype = new supertype ();" ในโหมดการรวมกันที่มีมรดก (ชนิดย่อย, supertype); ประสิทธิภาพของการสืบทอดการผสมผสานของปรสิต combinatorial นั้นสะท้อนให้เห็นว่ามันเรียกว่าตัวสร้างประเภทหลักเพียงครั้งเดียวเพื่อหลีกเลี่ยงการสร้างคุณสมบัติที่ไม่จำเป็นหรือซ้ำซ้อน ในเวลาเดียวกันห่วงโซ่ต้นแบบสามารถคงอยู่ได้ดังนั้นจึงสามารถใช้อินสแตนซ์ของและ isprototypeof () ได้ตามปกติ นี่เป็นวิธีการสืบทอดที่เหมาะที่สุดในปัจจุบันและปัจจุบันกำลังเปลี่ยนเป็นรุ่นนี้ (Yui ยังใช้โหมดนี้ด้วย)
โพสต์บล็อกนี้หมายถึง "JavaScript Advanced Programming รุ่นที่ 3" รหัสถูกเขียนใหม่และเฉพาะเจาะจงมากขึ้นและให้ความเห็นเพื่อให้ทุกคนเข้าใจได้ง่ายขึ้น หากคุณมีข้อมูลเชิงลึกที่เป็นเอกลักษณ์เกี่ยวกับการสืบทอด JS อย่าตระหนี่ ตอบกลับความคิดเห็นของคุณสำหรับการอ้างอิงของคุณ!