นี่เป็นโมเดลวัตถุต้นแบบที่ง่ายมากที่จะพิจารณาเป็นตัวอย่างระหว่างการอธิบายโดยยังไม่มีความคิดเห็น:
function Person(name){
this.name = name;
}
Person.prototype.getName = function(){
console.log(this.name);
}
var person = new Person("George");
มีบางจุดที่สำคัญที่เราต้องพิจารณาก่อนที่จะผ่านแนวคิดต้นแบบ
1- วิธีการทำงานของ JavaScript ทำงานได้จริง:
ในขั้นตอนแรกเราต้องคิดออกว่าฟังก์ชั่น JavaScript ใช้งานได้จริงอย่างไรในฐานะคลาสเช่นฟังก์ชั่นที่ใช้this
คำหลักในนั้นหรือเพียงแค่ฟังก์ชั่นปกติที่มีข้อโต้แย้งสิ่งที่มันทำและสิ่งที่มันส่งกลับ
สมมติว่าเราต้องการสร้างPerson
แบบจำลองวัตถุ แต่ในขั้นตอนนี้ผมจะพยายามที่จะทำในสิ่งที่แน่นอนเดียวกันโดยไม่ต้องใช้prototype
และnew
คำหลัก
ดังนั้นในขั้นตอนนี้functions
, objects
และthis
คำหลักทั้งหมดที่เรามี
คำถามแรกที่จะเป็นวิธีการที่this
คำหลักจะเป็นประโยชน์โดยไม่ต้องใช้new
คำหลัก
ดังนั้นเพื่อตอบว่าสมมุติว่าเรามีวัตถุว่างเปล่าและฟังก์ชันสองอย่างเช่น:
var person = {};
function Person(name){ this.name = name; }
function getName(){
console.log(this.name);
}
และตอนนี้โดยไม่ใช้new
คำสำคัญว่าเราจะใช้ฟังก์ชันเหล่านี้ได้อย่างไร ดังนั้น JavaScript มี 3 วิธีที่แตกต่างกัน:
วิธีแรกคือเพียงเรียกใช้ฟังก์ชันเป็นฟังก์ชันปกติ:
Person("George");
getName();//would print the "George" in the console
ในกรณีนี้นี้จะเป็นวัตถุบริบทปัจจุบันซึ่งมักจะเป็นระดับโลก window
วัตถุที่อยู่ในเบราว์เซอร์หรือในGLOBAL
Node.js
มันหมายความว่าเราจะมี window.name ในเบราว์เซอร์หรือ GLOBAL.name ใน Node.js โดยมี "George" เป็นค่า
ข เราสามารถแนบมันเข้ากับวัตถุเป็นคุณสมบัติ
- วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการดัดแปลงperson
วัตถุเปล่าเช่น:
person.Person = Person;
person.getName = getName;
วิธีนี้เราสามารถเรียกพวกเขาเช่น:
person.Person("George");
person.getName();// -->"George"
และตอนนี้person
วัตถุก็เหมือน:
Object {Person: function, getName: function, name: "George"}
- วิธีอื่นในการแนบคุณสมบัติกับวัตถุคือการใช้prototype
วัตถุนั้นที่สามารถค้นหาได้ในวัตถุ JavaScript ใด ๆ ที่มีชื่อ__proto__
และฉันพยายามอธิบายเล็กน้อยในส่วนสรุป ดังนั้นเราสามารถได้ผลลัพธ์ที่คล้ายกันโดยทำ:
person.__proto__.Person = Person;
person.__proto__.getName = getName;
แต่วิธีที่สิ่งที่เราทำจริง ๆ คือการแก้ไขObject.prototype
เพราะเมื่อใดก็ตามที่เราสร้างวัตถุ JavaScript โดยใช้ตัวอักษร ( { ... }
) มันจะถูกสร้างขึ้นตามObject.prototype
ซึ่งหมายความว่ามันจะได้รับการแนบกับวัตถุที่สร้างขึ้นใหม่เป็นแอตทริบิวต์ชื่อ__proto__
ดังนั้นถ้าเราเปลี่ยน ตามที่เราได้ทำกับข้อมูลโค้ดก่อนหน้านี้วัตถุ JavaScript ทั้งหมดจะเปลี่ยนไปไม่ใช่วิธีปฏิบัติที่ดี ดังนั้นสิ่งที่อาจเป็นแนวปฏิบัติที่ดีกว่าในขณะนี้:
person.__proto__ = {
Person: Person,
getName: getName
};
และตอนนี้วัตถุอื่น ๆ อยู่ในความสงบ แต่มันก็ดูเหมือนจะไม่เป็นวิธีที่ดี ดังนั้นเรายังมีอีกหนึ่งโซลูชั่น แต่เพื่อใช้โซลูชันนี้เราควรกลับไปที่บรรทัดของโค้ดที่person
มีการสร้างวัตถุ ( var person = {};
) จากนั้นเปลี่ยนเป็น:
var propertiesObject = {
Person: Person,
getName: getName
};
var person = Object.create(propertiesObject);
สิ่งที่มันคือการสร้าง JavaScript ใหม่Object
และแนบpropertiesObject
ไปกับ__proto__
แอตทริบิวต์ ดังนั้นเพื่อให้แน่ใจว่าคุณสามารถทำได้:
console.log(person.__proto__===propertiesObject); //true
แต่จุดที่ยุ่งยากก็คือคุณสามารถเข้าถึงคุณสมบัติทั้งหมดที่กำหนดไว้ใน__proto__
ระดับแรกของperson
วัตถุ (อ่านส่วนสรุปเพื่อดูรายละเอียดเพิ่มเติม)
ตามที่คุณเห็นโดยใช้สองวิธีthis
นี้จะชี้ไปที่person
วัตถุ
ค. JavaScript มีวิธีอื่นในการจัดเตรียมฟังก์ชันthis
ซึ่งใช้การโทรหรือใช้เพื่อเรียกใช้ฟังก์ชัน
ใช้ () วิธีการเรียกใช้ฟังก์ชั่นที่มีค่านี้และข้อโต้แย้งที่ได้รับให้เป็นอาร์เรย์ (หรือวัตถุเหมือนอาร์เรย์)
และ
การเรียก () วิธีการเรียกใช้ฟังก์ชั่นที่ได้รับค่านี้และข้อโต้แย้งให้เป็นรายบุคคล
ด้วยวิธีนี้ซึ่งเป็นที่ชื่นชอบเราสามารถเรียกฟังก์ชั่นของเราเช่น:
Person.call(person, "George");
หรือ
//apply is more useful when params count is not fixed
Person.apply(person, ["George"]);
getName.call(person);
getName.apply(person);
3 วิธีการเหล่านี้เป็นขั้นตอนเริ่มต้นที่สำคัญในการหาฟังก์ชันการทำงานของต้นแบบ
2- new
คำหลักทำงานอย่างไร
นี่เป็นขั้นตอนที่สองเพื่อทำความเข้าใจเกี่ยวกับการ.prototype
ทำงานนี่คือสิ่งที่ฉันใช้เพื่อจำลองกระบวนการ:
function Person(name){ this.name = name; }
my_person_prototype = { getName: function(){ console.log(this.name); } };
ในส่วนนี้ฉันจะพยายามทำตามขั้นตอนทั้งหมดที่ JavaScript ใช้โดยไม่ต้องใช้new
คำหลักและprototype
เมื่อคุณใช้new
คำหลัก ดังนั้นเมื่อเราทำnew Person("George")
, Person
ฟังก์ชั่นทำหน้าที่เป็นผู้สร้างเหล่านี้เป็นสิ่งที่ไม่ JavaScript หนึ่งโดยหนึ่ง:
ก่อนอื่นมันทำให้วัตถุที่ว่างเปล่าโดยทั่วไปจะมีแฮชว่างเปล่าเช่น:
var newObject = {};
ข ขั้นตอนต่อไปที่ JavaScript ใช้คือการแนบวัตถุต้นแบบทั้งหมดกับวัตถุที่สร้างขึ้นใหม่
เรามีmy_person_prototype
ที่นี่คล้ายกับวัตถุต้นแบบ
for(var key in my_person_prototype){
newObject[key] = my_person_prototype[key];
}
ไม่ใช่วิธีที่ JavaScript แนบคุณสมบัติที่กำหนดไว้ในต้นแบบ วิธีที่แท้จริงเกี่ยวข้องกับแนวคิดลูกโซ่ต้นแบบ
& b. แทนที่จะทำตามสองขั้นตอนเหล่านี้คุณสามารถได้ผลลัพธ์เดียวกันโดยทำดังนี้
var newObject = Object.create(my_person_prototype);
//here you can check out the __proto__ attribute
console.log(newObject.__proto__ === my_person_prototype); //true
//and also check if you have access to your desired properties
console.log(typeof newObject.getName);//"function"
ตอนนี้เราสามารถเรียกใช้getName
ฟังก์ชันในmy_person_prototype
:
newObject.getName();
ค. จากนั้นมันจะให้วัตถุนั้นแก่ผู้สร้าง
เราสามารถทำได้ด้วยตัวอย่างของเราเช่น:
Person.call(newObject, "George");
หรือ
Person.apply(newObject, ["George"]);
แล้วสร้างสามารถทำสิ่งที่มันต้องการเพราะนี้ภายในของตัวสร้างที่เป็นวัตถุที่ถูกสร้างขึ้นเพียง
ตอนนี้ผลลัพธ์สุดท้ายก่อนที่จะจำลองขั้นตอนอื่น ๆ : Object {name: "George"}
สรุป:
โดยทั่วไปเมื่อคุณใช้คำหลักใหม่ในฟังก์ชั่นคุณจะเรียกมันและฟังก์ชั่นนั้นทำหน้าที่เป็นตัวสร้างดังนั้นเมื่อคุณพูดว่า:
new FunctionName()
JavaScript ภายในทำให้วัตถุแฮที่ว่างเปล่าและจากนั้นมันจะช่วยให้วัตถุที่สร้างแล้วสร้างสามารถทำสิ่งที่มันต้องการเพราะนี้ภายในของตัวสร้างที่เป็นวัตถุที่ถูกสร้างขึ้นเพียงและจากนั้นก็จะช่วยให้คุณวัตถุแน่นอนว่า หากคุณยังไม่ได้ใช้คำสั่ง return ในฟังก์ชั่นของคุณหรือถ้าคุณใส่return undefined;
ท้ายฟังก์ชันเนื้อหาของคุณ
ดังนั้นเมื่อจาวาสคริปต์ไปค้นหาคุณสมบัติบนวัตถุสิ่งแรกที่มันทำคือมันค้นหาบนวัตถุนั้น แล้วก็มีคุณสมบัติลับ[[prototype]]
ที่เรามักจะชอบมัน__proto__
และคุณสมบัตินั้นคือสิ่งที่จาวาสคริปต์มีต่อไป และเมื่อมันมองผ่าน__proto__
ตราบใดที่มันเป็นวัตถุ JavaScript อีกตัวมันมีคุณสมบัติของมันเอง__proto__
มันจะขึ้นไปเรื่อย ๆ จนกว่ามันจะไปถึงจุดที่สิ่งต่อไป__proto__
นี้เป็นโมฆะ จุดเป็นวัตถุเดียวในจาวาสคริปต์ที่มี__proto__
คุณสมบัติเป็นโมฆะคือObject.prototype
วัตถุ:
console.log(Object.prototype.__proto__===null);//true
และนั่นคือวิธีที่มรดกทำงานใน JavaScript
ในคำอื่น ๆ เมื่อคุณมีคุณสมบัติต้นแบบในฟังก์ชั่นและคุณเรียกใหม่ในที่หลังจาก JavaScript เสร็จสิ้นการมองหาวัตถุที่สร้างขึ้นใหม่สำหรับคุณสมบัติมันจะไปดูฟังก์ชั่น.prototype
และยังเป็นไปได้ว่าวัตถุนี้มี ต้นแบบภายในของตัวเอง และอื่น ๆ