JavaScript เป็นภาษาที่มุ่งเน้นวัตถุ มีคำพูดคลาสสิกมากใน JavaScript: ทุกอย่างเป็นวัตถุ เนื่องจากเป็นวัตถุที่มุ่งเน้นจึงมีสามลักษณะสำคัญของวัตถุที่มุ่งเน้น: การห่อหุ้มการสืบทอดและความหลากหลาย ที่นี่เราพูดถึงมรดกของ JavaScript และเราจะพูดถึงอีกสองคนในภายหลัง
มรดกของ JavaScript นั้นไม่เหมือนกับ C ++ การสืบทอดของ C ++ ขึ้นอยู่กับคลาสในขณะที่การสืบทอดของ JavaScript ขึ้นอยู่กับต้นแบบ
ตอนนี้ปัญหาอยู่ที่นี่
ต้นแบบคืออะไร? สำหรับต้นแบบเราสามารถอ้างถึงคลาสใน C ++ และบันทึกคุณสมบัติและวิธีการของวัตถุ ตัวอย่างเช่นเรามาเขียนวัตถุง่ายๆ
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นสัตว์ (ชื่อ) {
this.name = ชื่อ;
-
Animal.prototype.setName = function (ชื่อ) {
this.name = ชื่อ;
-
Var Animal = สัตว์ใหม่ ("Wangwang");
เราจะเห็นได้ว่านี่เป็นสัตว์วัตถุซึ่งมีชื่อแอตทริบิวต์และชื่อวิธีการ โปรดทราบว่าเมื่อมีการแก้ไขต้นแบบเช่นการเพิ่มวิธีการทุกอินสแตนซ์ของวัตถุจะแบ่งปันวิธีนี้ ตัวอย่างเช่น
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นสัตว์ (ชื่อ) {
this.name = ชื่อ;
-
Var Animal = สัตว์ใหม่ ("Wangwang");
ในเวลานี้สัตว์มีแอตทริบิวต์ชื่อเท่านั้น ถ้าเราเพิ่มประโยค
การคัดลอกรหัสมีดังนี้:
Animal.prototype.setName = function (ชื่อ) {
this.name = ชื่อ;
-
ในเวลานี้สัตว์จะมีวิธีการตั้งชื่อ
สำเนาการสืบทอด - เริ่มต้นจากวัตถุที่ว่างเปล่าเรารู้ว่าในประเภทพื้นฐานของ JS มีประเภทที่เรียกว่าวัตถุและอินสแตนซ์พื้นฐานที่สุดคือวัตถุที่ว่างเปล่านั่นคืออินสแตนซ์ที่สร้างขึ้นโดยการเรียกวัตถุใหม่ () โดยตรงหรือประกาศด้วยตัวอักษร {} วัตถุที่ว่างเปล่าคือ "วัตถุที่สะอาด" โดยมีคุณสมบัติและวิธีการที่กำหนดไว้ล่วงหน้าเท่านั้นในขณะที่วัตถุอื่น ๆ ทั้งหมดได้รับการสืบทอดมาจากวัตถุเปล่าดังนั้นวัตถุทั้งหมดจึงมีคุณสมบัติและวิธีการที่กำหนดไว้ล่วงหน้าเหล่านี้ ต้นแบบเป็นอินสแตนซ์ของวัตถุ ความหมายของต้นแบบคือ: หากตัวสร้างมีวัตถุต้นแบบ A อินสแตนซ์ที่สร้างโดยตัวสร้างจะต้องคัดลอกจาก A เนื่องจากอินสแตนซ์ถูกคัดลอกจากวัตถุ A อินสแตนซ์จะต้องสืบทอดคุณสมบัติทั้งหมดวิธีการและคุณสมบัติอื่น ๆ ของ A ดังนั้นวิธีการจำลองแบบ วิธีที่ 1: สร้างสำเนาแต่ละอินสแตนซ์ที่สร้างขึ้นจะถูกคัดลอกจากต้นแบบและอินสแตนซ์ใหม่จะใช้พื้นที่หน่วยความจำเดียวกับต้นแบบ แม้ว่าสิ่งนี้จะทำให้ OBJ1 และ OBJ2 "สอดคล้องกันอย่างสมบูรณ์" กับต้นแบบของพวกเขา แต่ก็ไม่ประหยัดมาก - การบริโภคพื้นที่หน่วยความจำจะเพิ่มขึ้นอย่างรวดเร็ว ดังที่แสดงในภาพ:
วิธีที่ 2: คัดลอกการเขียนกลยุทธ์นี้มาจากเทคโนโลยีของระบบการหลอกลวงที่สอดคล้องกัน: คัดลอกการเขียน ตัวอย่างทั่วไปของการฉ้อโกงประเภทนี้คือไลบรารีลิงก์แบบไดนามิก (DDL) ในระบบปฏิบัติการซึ่งพื้นที่หน่วยความจำจะถูกคัดลอกอยู่เสมอในการเขียน ดังที่แสดงในภาพ:
เราเพียงแค่ต้องระบุในระบบที่ OBJ1 และ OBJ2 เทียบเท่ากับต้นแบบของพวกเขาดังนั้นเมื่ออ่านเราต้องทำตามคำแนะนำในการอ่านต้นแบบเท่านั้น เมื่อเราจำเป็นต้องเขียนคุณสมบัติของวัตถุ (เช่น OBJ2) เราจะคัดลอกภาพต้นแบบและทำให้การดำเนินการที่ตามมาชี้ไปที่ภาพ ดังที่แสดงในภาพ:
ข้อได้เปรียบของวิธีนี้คือเราไม่จำเป็นต้องมีหน่วยความจำจำนวนมากค่าใช้จ่ายเมื่อสร้างอินสแตนซ์และคุณลักษณะการอ่าน เราใช้รหัสบางส่วนเพื่อจัดสรรหน่วยความจำเมื่อเขียนครั้งแรกและนำรหัสและค่าใช้จ่ายหน่วยความจำ แต่จะไม่มีค่าใช้จ่ายดังกล่าวตั้งแต่นั้นมาเนื่องจากประสิทธิภาพของการเข้าถึงภาพและการเข้าถึงต้นแบบนั้นสอดคล้องกัน อย่างไรก็ตามสำหรับระบบที่มักจะเขียนการดำเนินงานวิธีนี้ไม่ประหยัดกว่าวิธีการก่อนหน้านี้ วิธีที่ 3: การอ่าน Traversal วิธีนี้จะเปลี่ยนความละเอียดของสำเนาจากต้นแบบเป็นสมาชิก วิธีนี้มีลักษณะโดยการคัดลอกข้อมูลสมาชิกลงในภาพอินสแตนซ์เฉพาะเมื่อเขียนสมาชิกของอินสแตนซ์ เมื่อเขียนคุณสมบัติของวัตถุเช่น (obj2.value = 10) ค่าแอตทริบิวต์ที่ชื่อจะถูกสร้างและวางไว้ในรายการสมาชิกของวัตถุ OBJ2 ดูภาพ:
จะพบได้ว่า OBJ2 ยังคงอ้างอิงถึงต้นแบบและไม่มีอินสแตนซ์วัตถุที่มีขนาดเท่ากันกับต้นแบบถูกสร้างขึ้นในระหว่างการดำเนินการ ด้วยวิธีนี้การดำเนินการเขียนไม่ได้นำไปสู่การจัดสรรหน่วยความจำจำนวนมากดังนั้นการใช้หน่วยความจำจึงประหยัด ความแตกต่างคือ OBJ2 (และอินสแตนซ์วัตถุทั้งหมด) จำเป็นต้องรักษารายชื่อสมาชิก รายชื่อสมาชิกนี้เป็นไปตามกฎสองข้อ: รับประกันได้ว่าจะเข้าถึงก่อนเมื่ออ่าน หากไม่มีการระบุแอตทริบิวต์ในวัตถุให้ลองสำรวจห่วงโซ่ต้นแบบทั้งหมดของวัตถุจนกว่าต้นแบบจะว่างเปล่าหรือพบคุณสมบัติ ห่วงโซ่ต้นแบบจะถูกกล่าวถึงในภายหลัง เห็นได้ชัดว่าในสามวิธีการอ่าน Traversal เป็นประสิทธิภาพที่ดีที่สุด ดังนั้นการสืบทอดการสืบทอดต้นแบบของ JavaScript จึงถูกอ่าน Traversal ผู้สร้างที่คุ้นเคยกับ C ++ จะสับสนอย่างแน่นอนหลังจากอ่านรหัสของวัตถุด้านบน เป็นเรื่องง่ายที่จะเข้าใจโดยไม่ต้องใช้คำหลักของคลาสหลังจากทั้งหมดมีคำหลักของฟังก์ชั่น แต่คำหลักจะแตกต่างกัน แต่สิ่งที่เกี่ยวกับตัวสร้าง? ในความเป็นจริง JavaScript ยังมีตัวสร้างที่คล้ายกัน แต่พวกเขาเรียกว่าตัวสร้าง เมื่อใช้ตัวดำเนินการใหม่ตัวสร้างจะถูกเรียกและสิ่งนี้ถูกผูกไว้เป็นวัตถุ ตัวอย่างเช่นเราใช้รหัสต่อไปนี้
การคัดลอกรหัสมีดังนี้:
Var Animal = Animal ("Wangwang");
สัตว์จะไม่ได้กำหนด บางคนจะบอกว่าไม่มีค่าตอบแทนที่ไม่ได้กำหนดไว้แน่นอน ถ้าคุณเปลี่ยนคำจำกัดความของวัตถุสัตว์:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นสัตว์ (ชื่อ) {
this.name = ชื่อ;
คืนสิ่งนี้;
-
เดาว่าตอนนี้สัตว์คืออะไร?
ในเวลานี้สัตว์ได้กลายเป็นหน้าต่าง ความแตกต่างคือมันขยายหน้าต่างเพื่อให้หน้าต่างนั้นมีแอตทริบิวต์ชื่อ นี่เป็นเพราะค่าเริ่มต้นไปยังหน้าต่างนั่นคือตัวแปรระดับบนสุดโดยไม่ระบุ โดยการเรียกคำหลักใหม่ที่สร้างตัวสร้างจะถูกเรียกอย่างถูกต้อง ดังนั้นวิธีหลีกเลี่ยงคำหลักใหม่ที่คนใช้พลาดไป? เราสามารถทำการเปลี่ยนแปลงเล็กน้อย:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นสัตว์ (ชื่อ) {
ถ้า (! (อินสแตนซ์ของสัตว์นี้)) {
คืนสัตว์ใหม่ (ชื่อ);
-
this.name = ชื่อ;
-
นี่จะเป็นเรื่องที่เข้าใจผิด คอนสตรัคเตอร์ยังมีการใช้งานอื่นซึ่งระบุว่าวัตถุใดที่เป็นของอินสแตนซ์ เราสามารถใช้อินสแตนซ์ของการตัดสิน แต่อินสแตนซ์จะกลับมาจริงกับวัตถุบรรพบุรุษและวัตถุจริงเมื่อสืบทอดดังนั้นจึงไม่เหมาะสมมาก เมื่อตัวสร้างถูกเรียกว่าใหม่มันจะชี้ไปที่วัตถุปัจจุบันโดยค่าเริ่มต้น
การคัดลอกรหัสมีดังนี้:
console.log (iment.prototype.constructor === สัตว์); // จริง
เราสามารถคิดแตกต่างกันได้: ต้นแบบไม่มีค่าที่จุดเริ่มต้นของฟังก์ชั่นและการใช้งานอาจเป็นตรรกะต่อไปนี้
// set __proto__ เป็นสมาชิกในตัวของฟังก์ชั่น get_prototyoe () เป็นวิธีการของมัน
การคัดลอกรหัสมีดังนี้:
var __proto__ = null;
ฟังก์ชั่น get_prototype () {
ถ้า (! __ proto__) {
__proto__ = วัตถุใหม่ ();
__proto __. constructor = this;
-
กลับ __proto__;
-
ประโยชน์นี้คือการหลีกเลี่ยงการสร้างอินสแตนซ์ของวัตถุสำหรับทุกฟังก์ชั่นที่ประกาศโดยประหยัดค่าใช้จ่าย ตัวสร้างสามารถแก้ไขได้ซึ่งจะกล่าวถึงในภายหลัง ฉันเชื่อว่าทุกคนรู้ว่าการสืบทอดอะไรขึ้นอยู่กับต้นแบบดังนั้นพวกเขาจึงไม่แสดงขีด จำกัด ที่ต่ำกว่าไอคิวของพวกเขา
มีการสืบทอด JS หลายประเภทต่อไปนี้เป็นสองประเภท
1. วิธีที่ 1 วิธีนี้ใช้กันมากที่สุดและมีความปลอดภัยที่ดีกว่า มากำหนดวัตถุสองอย่างก่อน
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นสัตว์ (ชื่อ) {
this.name = ชื่อ;
-
ฟังก์ชั่นสุนัข (อายุ) {
this.age = อายุ;
-
var dog = สุนัขใหม่ (2);
มันง่ายมากที่จะสร้างมรดกชี้ต้นแบบของวัตถุเด็กไปที่อินสแตนซ์ของวัตถุพาเรนต์ (โปรดทราบว่ามันเป็นอินสแตนซ์ไม่ใช่วัตถุ)
การคัดลอกรหัสมีดังนี้:
dog.prototype = สัตว์ใหม่ ("Wangwang");
ในเวลานี้สุนัขจะมีสองคุณลักษณะชื่อและอายุ และหากผู้ให้บริการอินสแตนซ์ของสุนัขใช้สำหรับสุนัข
การคัดลอกรหัสมีดังนี้:
console.log (สัตว์อินสแตนซ์ของสัตว์); // จริง
console.log (สุนัขอินสแตนซ์ของสุนัข); // เท็จ
สิ่งนี้ประสบความสำเร็จในมรดก แต่มีปัญหาเล็ก ๆ น้อย ๆ
การคัดลอกรหัสมีดังนี้:
console.log (dog.prototype.constructor === สัตว์); // จริง
console.log (dog.prototype.constructor === สุนัข); // เท็จ
คุณจะเห็นได้ว่าวัตถุที่ชี้ไปที่ตัวสร้างมีการเปลี่ยนแปลงซึ่งไม่ตรงตามวัตถุประสงค์ของเรา เราไม่สามารถระบุได้ว่าอินสแตนซ์ของเราเป็นของใคร ดังนั้นเราสามารถเพิ่มหนึ่งประโยค:
การคัดลอกรหัสมีดังนี้:
dog.prototype.constructor = dog;
ลองมาดูกันอีกครั้ง:
การคัดลอกรหัสมีดังนี้:
console.log (สัตว์อินสแตนซ์ของสัตว์); // เท็จ
console.log (สุนัขอินสแตนซ์ของสุนัข); // จริง
เสร็จแล้ว. วิธีนี้เป็นลิงค์ในการบำรุงรักษาห่วงโซ่ต้นแบบซึ่งจะอธิบายรายละเอียดด้านล่าง 2. วิธีที่ 2 วิธีนี้มีประโยชน์และข้อเสีย แต่ข้อเสียมีค่ามากกว่าผลประโยชน์ ดูรหัสก่อน
การคัดลอกรหัสมีดังนี้:
<name pre = "code"> function iment (ชื่อ) {
this.name = ชื่อ;
-
Animal.prototype.setName = function (ชื่อ) {
this.name = ชื่อ;
-
ฟังก์ชั่นสุนัข (อายุ) {
this.age = อายุ;
-
dog.prototype = iment.prototype;
สิ่งนี้ช่วยให้การคัดลอกต้นแบบ
ข้อดีของวิธีนี้คือไม่จำเป็นต้องมีการสร้างอินสแตนซ์ของวัตถุ (เปรียบเทียบกับวิธีที่ 1) ประหยัดทรัพยากร ข้อเสียก็ชัดเจนเช่นกัน นอกเหนือจากปัญหาเดียวกันกับข้างต้นนั่นคือตัวสร้างชี้ไปที่วัตถุหลักแล้วมันสามารถคัดลอกคุณสมบัติและวิธีการที่ประกาศโดยวัตถุหลักที่มีต้นแบบ กล่าวคือในรหัสด้านบนแอตทริบิวต์ชื่อของวัตถุสัตว์ไม่สามารถคัดลอกได้ แต่วิธีการตั้งชื่อสามารถคัดลอกได้ สิ่งที่ร้ายแรงที่สุดคือการปรับเปลี่ยนต้นแบบของวัตถุเด็กจะส่งผลกระทบต่อต้นแบบของวัตถุหลักนั่นคืออินสแตนซ์ที่ประกาศโดยวัตถุทั้งสองจะได้รับผลกระทบ ดังนั้นจึงไม่แนะนำให้ใช้วิธีนี้
ห่วงโซ่ต้นแบบ
ใครก็ตามที่เขียนเกี่ยวกับมรดกรู้ว่าการสืบทอดสามารถสืบทอดได้จากหลายระดับ และใน JS สิ่งนี้จะเป็นห่วงโซ่ต้นแบบ บทความข้างต้นยังกล่าวถึงห่วงโซ่ต้นแบบหลายครั้งดังนั้นห่วงโซ่ต้นแบบคืออะไร? อย่างน้อยอินสแตนซ์ควรมีแอตทริบิวต์โปรโตที่ชี้ไปที่ต้นแบบซึ่งเป็นพื้นฐานของระบบวัตถุใน JavaScript อย่างไรก็ตามคุณสมบัตินี้มองไม่เห็นและเราเรียกมันว่า "ห่วงโซ่ต้นแบบภายใน" เพื่อแยกแยะความแตกต่างจาก "ตัวสร้างต้นแบบตัวสร้าง" ซึ่งประกอบด้วยต้นแบบของตัวสร้าง (นั่นคือสิ่งที่เรามักเรียกว่า "ห่วงโซ่ต้นแบบ") ก่อนอื่นสร้างความสัมพันธ์การสืบทอดอย่างง่ายตามรหัสข้างต้น:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นสัตว์ (ชื่อ) {
this.name = ชื่อ;
-
ฟังก์ชั่นสุนัข (อายุ) {
this.age = อายุ;
-
Var Animal = สัตว์ใหม่ ("Wangwang");
dog.prototype = สัตว์;
var dog = สุนัขใหม่ (2);
เพื่อเป็นการเตือนความจำตามที่กล่าวไว้ก่อนหน้านี้วัตถุทั้งหมดสืบทอดวัตถุที่ว่างเปล่า ดังนั้นเราสร้างห่วงโซ่ต้นแบบ:
เราจะเห็นได้ว่าต้นแบบของวัตถุเด็กชี้ไปที่อินสแตนซ์ของวัตถุแม่ซึ่งสร้างห่วงโซ่ต้นแบบตัวสร้าง วัตถุโปรโตภายในของอินสแตนซ์เด็กก็เป็นอินสแตนซ์ที่ชี้ไปที่วัตถุหลักซึ่งสร้างห่วงโซ่ต้นแบบภายใน เมื่อเราต้องการค้นหาคุณสมบัติรหัสจะคล้ายกับ
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น getattrfromobj (attr, obj) {
if (typeof (obj) === "object") {
var proto = obj;
ในขณะที่ (โปรโต) {
if (proto.hasownproperty (attr)) {
ส่งคืนโปรโต [attr];
-
proto = proto .__ proto__;
-
-
กลับมาไม่ได้กำหนด;
-
ในตัวอย่างนี้ถ้าเราค้นหาแอตทริบิวต์ชื่อใน DOG มันจะถูกค้นหาในรายชื่อสมาชิกใน DOG แน่นอนว่าจะไม่พบเพราะตอนนี้รายชื่อสมาชิกของสุนัขเป็นเพียงอายุรายการเท่านั้น จากนั้นมันจะยังคงค้นหาตามห่วงโซ่ต้นแบบนั่นคืออินสแตนซ์ที่ชี้ไปที่. proto นั่นคือในสัตว์ค้นหาแอตทริบิวต์ชื่อและส่งคืน หากการค้นหาเป็นคุณสมบัติที่ไม่มีอยู่เมื่อไม่สามารถพบได้ในสัตว์มันจะทำการค้นหาด้วย. proto ต่อไปค้นหาวัตถุที่ว่างเปล่าจากนั้นค้นหาต่อไปด้วย. proto และ. proto ของวัตถุที่ว่างเปล่าเป็นโมฆะ
การบำรุงรักษาโซ่ต้นแบบเราตั้งคำถามเมื่อเราพูดคุยเกี่ยวกับการสืบทอดต้นแบบตอนนี้ เมื่อใช้วิธีการที่ 10 เพื่อสร้างการสืบทอดตัวสร้างของอินสแตนซ์ของวัตถุลูกจะชี้ไปที่วัตถุหลัก ข้อดีของสิ่งนี้คือเราสามารถเข้าถึงห่วงโซ่ต้นแบบผ่านแอตทริบิวต์คอนสตรัคเตอร์และข้อเสียก็ชัดเจนเช่นกัน วัตถุที่มีอินสแตนซ์ควรชี้ไปที่ตัวเองเช่น
การคัดลอกรหัสมีดังนี้:
(OBJ ใหม่ ()). Prototype.Constructor === OBJ;
จากนั้นหลังจากที่เราเขียนคุณสมบัติต้นแบบใหม่ตัวสร้างของอินสแตนซ์ที่สร้างโดยวัตถุเด็กไม่ได้ชี้ไปที่ตัวเอง! สิ่งนี้ขัดกับความตั้งใจดั้งเดิมของตัวสร้าง เราพูดถึงวิธีแก้ปัญหาด้านบน:
การคัดลอกรหัสมีดังนี้:
dog.prototype = สัตว์ใหม่ ("Wangwang");
dog.prototype.constructor = dog;
ดูเหมือนว่าไม่มีอะไรผิดปกติ แต่ในความเป็นจริงสิ่งนี้ทำให้เกิดปัญหาใหม่เพราะเราจะพบว่าเราไม่สามารถกลับไปที่ห่วงโซ่ต้นแบบได้เพราะเราไม่สามารถหาวัตถุหลักได้และแอตทริบิวต์. proto ของห่วงโซ่ต้นแบบภายในไม่สามารถเข้าถึงได้ ดังนั้น SpiderMonkey ให้การปรับปรุง: เพิ่มคุณสมบัติที่ชื่อว่า __proto__ ลงในวัตถุที่สร้างขึ้นซึ่งชี้ไปที่ต้นแบบที่ใช้โดยตัวสร้าง ด้วยวิธีนี้การดัดแปลงใด ๆ ของตัวสร้างจะไม่ส่งผลกระทบต่อมูลค่าของ __proto__ ทำให้สะดวกในการรักษาตัวสร้าง
อย่างไรก็ตามมีอีกสองปัญหา:
__proto__ เป็นสิ่งที่เขียนขึ้นใหม่ซึ่งหมายความว่ายังมีความเสี่ยงเมื่อใช้งาน
__proto__ เป็นการประมวลผลพิเศษของ Spidermonkey และไม่สามารถใช้ในเครื่องยนต์อื่น ๆ (เช่น JScript)
มีอีกวิธีหนึ่งที่เราจะรักษาคุณสมบัติตัวสร้างของต้นแบบและเริ่มต้นคุณสมบัติของตัวสร้างของอินสแตนซ์ภายในฟังก์ชันคอนสตรัคเตอร์คลาสย่อย
รหัสมีดังนี้: เขียนวัตถุเด็กใหม่
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่นสุนัข (อายุ) {
this.constructor = arguments.callee;
this.age = อายุ;
-
dog.prototype = สัตว์ใหม่ ("Wangwang");
ด้วยวิธีนี้ตัวสร้างของทุกกรณีของวัตถุเด็กชี้ไปที่วัตถุอย่างถูกต้องในขณะที่ตัวสร้างของต้นแบบชี้ไปที่วัตถุหลัก แม้ว่าวิธีนี้จะไม่มีประสิทธิภาพเนื่องจากแอตทริบิวต์ตัวสร้างจะต้องเขียนใหม่ทุกครั้งที่มีการสร้างอินสแตนซ์ แต่ก็ไม่ต้องสงสัยเลยว่าวิธีนี้สามารถแก้ไขความขัดแย้งก่อนหน้านี้ได้อย่างมีประสิทธิภาพ ES5 คำนึงถึงสิ่งนี้และแก้ไขปัญหานี้ได้อย่างสมบูรณ์: Object.getPrototypeof () สามารถใช้งานได้ตลอดเวลาเพื่อให้ได้ต้นแบบจริงของวัตถุโดยไม่ต้องเข้าถึงตัวสร้างหรือบำรุงรักษาห่วงโซ่ต้นแบบภายนอก ดังนั้นดังที่ได้กล่าวไว้ในส่วนก่อนหน้านี้เราสามารถเขียนใหม่ได้ดังนี้:
การคัดลอกรหัสมีดังนี้:
ฟังก์ชั่น getattrfromobj (attr, obj) {
if (typeof (obj) === "object") {
ทำ {
var proto = object.getPrototypeof (Dog);
ถ้า (proto [attain]) {
ส่งคืนโปรโต [attr];
-
-
ในขณะที่ (โปรโต);
-
กลับมาไม่ได้กำหนด;
-
แน่นอนว่าวิธีนี้สามารถใช้ในเบราว์เซอร์ที่รองรับ ES5 เท่านั้น เพื่อให้สามารถย้อนหลังได้เรายังต้องพิจารณาวิธีการก่อนหน้านี้ วิธีที่เหมาะสมกว่าคือการรวมและห่อหุ้มสองวิธีนี้ ฉันเชื่อว่าผู้อ่านดีมากในเรื่องนี้ดังนั้นฉันจะไม่อัปลักษณ์ที่นี่