ฉันพยายามทำความเข้าใจเบื้องหลังฉากหลังของจาวาสคริปต์และติดอยู่ในความเข้าใจในการสร้างวัตถุในตัววัตถุและฟังก์ชั่นพิเศษและความสัมพันธ์ระหว่างพวกเขา
มันซับซ้อนมันง่ายต่อการเข้าใจผิดและหนังสือ Javascript มือใหม่มากมายหลายเล่มเข้าใจผิดดังนั้นอย่าเชื่อใจทุกสิ่งที่คุณอ่าน
ฉันเป็นหนึ่งในผู้ดำเนินการของโปรแกรม JS ของ Microsoft ในปี 1990 และในคณะกรรมการมาตรฐานและฉันทำข้อผิดพลาดจำนวนมากเมื่อรวมคำตอบนี้เข้าด้วยกัน (ถึงแม้ว่าฉันจะไม่ได้ทำงานในเรื่องนี้มานานกว่า 15 ปีฉันก็อาจได้รับการให้อภัย) มันเป็นเรื่องยุ่งยาก แต่เมื่อคุณเข้าใจการถ่ายทอดทางพันธุกรรมต้นแบบแล้วมันก็สมเหตุสมผล
เมื่อฉันอ่านว่าวัตถุในตัวทั้งหมดเช่น Array, String ฯลฯ เป็นส่วนขยาย (สืบทอด) จาก Object ฉันคิดว่า Object เป็นวัตถุแรกที่สร้างขึ้นในวัตถุที่สร้างขึ้นและส่วนที่เหลือของวัตถุสืบทอดมาจากมัน
เริ่มต้นด้วยการทิ้งทุกสิ่งที่คุณรู้เกี่ยวกับการสืบทอดตามระดับ JS ใช้การสืบทอดตามต้นแบบ
ถัดไปตรวจสอบให้แน่ใจว่าคุณมีคำจำกัดความที่ชัดเจนมากในหัวของความหมายของ "การสืบทอด" ผู้ใช้ภาษา OO เช่น C # หรือ Java หรือ C ++ คิดว่าการสืบทอดหมายถึงการพิมพ์ย่อย แต่การสืบทอดไม่ได้หมายถึงการพิมพ์ย่อย การสืบทอดหมายความว่าสมาชิกของสิ่งหนึ่งยังเป็นสมาชิกของอีกสิ่งหนึ่งด้วย มันไม่จำเป็นต้องหมายความว่ามีความสัมพันธ์ระหว่าง subtyping สิ่งเหล่านั้น! ความเข้าใจผิดมากมายในทฤษฎีประเภทเป็นผลมาจากคนไม่ทราบว่ามีความแตกต่าง
แต่มันก็ไม่สมเหตุสมผลเมื่อคุณรู้ว่า Object สามารถสร้างได้โดยฟังก์ชั่นเท่านั้น แต่ฟังก์ชั่นนั้นก็ไม่ได้มี แต่วัตถุของ Function
นี่เป็นเพียงแค่ความเท็จ วัตถุบางอย่างจะไม่ได้สร้างขึ้นโดยการเรียกฟังก์ชั่นบางอย่างnew F Fวัตถุบางอย่างถูกสร้างขึ้นโดยรันไทม์ของ JS ไม่มีอะไรเลย มีไข่ที่ไม่ได้ถูกวางโดยไก่ใด ๆ พวกเขาเพิ่งสร้างขึ้นโดยรันไทม์เมื่อมันเริ่มต้นขึ้น
สมมติว่ากฎคืออะไรและอาจช่วยได้
- ทุกอินสแตนซ์ของวัตถุมีวัตถุต้นแบบ
nullในบางกรณีที่ต้นแบบสามารถ
- ถ้าคุณเข้าถึงสมาชิกบนอินสแตนซ์ของวัตถุและวัตถุนั้นไม่มีสมาชิกนั้นวัตถุจะเลื่อนไปที่ต้นแบบหรือหยุดหากต้นแบบนั้นเป็นโมฆะ
prototypeสมาชิกของวัตถุที่เป็นปกติไม่ได้ต้นแบบของวัตถุ
- ค่อนข้าง
prototypeสมาชิกของฟังก์ชั่น F new F()วัตถุเป็นวัตถุที่จะกลายเป็นต้นแบบของวัตถุที่สร้างขึ้นโดย
- ในการใช้งานบางอย่างอินสแตนซ์รับ
__proto__สมาชิกที่ให้ต้นแบบจริง ๆ (ตอนนี้เลิกใช้แล้วอย่าพึ่งมัน)
- วัตถุฟังก์ชั่นจะได้รับวัตถุเริ่มต้นใหม่ที่กำหนดให้
prototypeเมื่อพวกเขาถูกสร้างขึ้น
Function.prototypeต้นแบบของวัตถุฟังก์ชั่นเป็นของหลักสูตร
มาสรุปกันเถอะ
- ต้นแบบของ
ObjectคือFunction.prototype
Object.prototype เป็นวัตถุต้นแบบวัตถุ
- ต้นแบบของ
Object.prototypeคือnull
- ต้นกำเนิดของ
FunctionคือFunction.prototype- นี่เป็นหนึ่งในสถานการณ์ที่หายากซึ่งFunction.prototypeต้นแบบของFunction!
Function.prototype เป็นวัตถุต้นแบบฟังก์ชั่น
- ต้นแบบของ
Function.prototypeคือObject.prototype
สมมุติว่าเราสร้างฟังก์ชั่น Foo
- ต้นแบบของการมี
FooFunction.prototype
Foo.prototype เป็นวัตถุต้นแบบฟู
- ต้นแบบของการมี
Foo.prototypeObject.prototype
สมมติว่าเราพูด new Foo()
- ต้นแบบของวัตถุใหม่คือ
Foo.prototype
ตรวจสอบให้แน่ใจว่าเหมาะสม มาวาดกันเถอะ Ovals เป็นวัตถุวัตถุ ขอบมี__proto__ความหมายว่า "ต้นแบบของ" หรือprototypeความหมาย " prototypeคุณสมบัติของ"

รันไทม์ทั้งหมดที่ต้องทำคือสร้างวัตถุเหล่านั้นทั้งหมดและกำหนดคุณสมบัติต่าง ๆ ให้สอดคล้องกัน ฉันแน่ใจว่าคุณสามารถดูว่าจะทำอย่างไร
ลองมาดูตัวอย่างที่ทดสอบความรู้ของคุณ
function Car(){ }
var honda = new Car();
print(honda instanceof Car);
print(honda.constructor == Car);
สิ่งที่พิมพ์นี้
แล้วมันinstanceofหมายความว่าอะไร? honda instanceof Carหมายความว่า " Car.prototypeเท่ากับวัตถุใด ๆ ในhondaโซ่ต้นแบบ"
ใช่แล้ว. hondaต้นแบบคือCar.prototypeดังนั้นเราก็เสร็จแล้ว สิ่งนี้พิมพ์จริง
แล้วอันที่สองล่ะ?
honda.constructorCar.prototypeไม่ได้อยู่ดังนั้นเราจึงปรึกษาต้นแบบซึ่งเป็น เมื่อCar.prototypeวัตถุถูกสร้างขึ้นมันจะได้รับคุณสมบัติโดยอัตโนมัติconstructorเท่ากับCarสิ่งนี้จึงเป็นจริง
แล้วเรื่องนี้ล่ะ
var Animal = new Object();
function Reptile(){ }
Reptile.prototype = Animal;
var lizard = new Reptile();
print(lizard instanceof Reptile);
print(lizard.constructor == Reptile);
โปรแกรมนี้พิมพ์อะไร
อีกครั้งlizard instanceof Reptileหมายถึง " Reptile.prototypeเท่ากับวัตถุใด ๆ ในlizardโซ่ต้นแบบ"
ใช่แล้ว. lizardต้นแบบคือReptile.prototypeดังนั้นเราก็เสร็จแล้ว สิ่งนี้พิมพ์จริง
ตอนนี้เกี่ยวกับ
print(lizard.constructor == Reptile);
คุณอาจคิดว่าสิ่งนี้พิมพ์ออกมาได้จริงเนื่องจากlizardสร้างด้วยnew Reptileแต่คุณจะผิด เหตุผลมันออกมา
- ไม่
lizardได้มีconstructorทรัพย์สิน? ไม่เลยเราดูต้นแบบ
- ต้นแบบของการ
lizardมีที่ซึ่งเป็นReptile.prototypeAnimal
- ไม่
Animalได้มีconstructorทรัพย์สิน? ไม่เลยเราดูที่ต้นแบบ
- ต้นแบบของ
Animalเป็นObject.prototypeและถูกสร้างขึ้นโดยรันไทม์และเท่ากับObject.prototype.constructorObject
- ดังนั้นสิ่งนี้จึงพิมพ์ผิด
เราควรจะพูดReptile.prototype.constructor = Reptile;ในจุดนั้น แต่เราจำไม่ได้!
ตรวจสอบให้แน่ใจว่าทั้งหมดเหมาะสมกับคุณ วาดกล่องและลูกศรบางส่วนหากยังคงสับสน
สิ่งที่สับสนอย่างยิ่งคือถ้าฉันconsole.log(Function.prototype)พิมพ์ฟังก์ชั่น แต่เมื่อฉันพิมพ์console.log(Object.prototype)มันจะพิมพ์วัตถุ ทำไมFunction.prototypeฟังก์ชั่นเมื่อมันถูกหมายถึงเป็นวัตถุ?
undefinedต้นแบบฟังก์ชั่นที่ถูกกำหนดให้เป็นหน้าที่ซึ่งเมื่อเรียกว่าผลตอบแทน เรารู้แล้วว่าFunction.prototypeมันFunctionเป็นต้นแบบที่แปลกพอสมควร ดังนั้นจึงFunction.prototype()เป็นเรื่องถูกกฎหมายและเมื่อคุณทำคุณจะได้รับundefinedกลับ ดังนั้นมันจึงเป็นฟังก์ชั่น
Objectต้นแบบไม่ได้มีคุณสมบัตินี้; มันไม่สามารถโทรออกได้ มันเป็นแค่วัตถุ
เมื่อคุณconsole.log(Function.prototype.constructor)เป็นอีกฟังก์ชั่น
Function.prototype.constructorเป็นเพียงFunctionชัดเจน และFunctionเป็นฟังก์ชั่น
ตอนนี้คุณจะใช้บางสิ่งเพื่อสร้างมันเองได้อย่างไร (Mind = blown)
คุณคิดมากเกินไป สิ่งที่จำเป็นทั้งหมดก็คือรันไทม์จะสร้างกลุ่มวัตถุเมื่อมันเริ่มขึ้น วัตถุเป็นเพียงตารางการค้นหาที่เชื่อมโยงสตริงกับวัตถุ เมื่อรันไทม์เริ่มขึ้นทั้งหมดจะได้ทำคือการสร้างวัตถุว่างเปล่าไม่กี่โหลและจากนั้นเริ่มกำหนดprototype, __proto__, constructorและอื่น ๆ คุณสมบัติของแต่ละวัตถุจนกว่าพวกเขาจะทำให้กราฟที่พวกเขาต้องการที่จะทำให้
มันจะมีประโยชน์ถ้าคุณทำแผนภาพนั้นที่ฉันให้ไว้ด้านบนแล้วเพิ่มconstructorขอบเข้าไป คุณจะเห็นได้อย่างรวดเร็วว่านี่เป็นกราฟวัตถุที่ง่ายมากและรันไทม์จะไม่มีปัญหาในการสร้าง
การออกกำลังกายที่ดีก็คือการทำด้วยตัวเอง ที่นี่ฉันจะเริ่มต้นให้คุณออก เราจะใช้my__proto__เพื่อหมายถึง "วัตถุต้นแบบของ" และmyprototypeหมายถึง "คุณสมบัติต้นแบบของ"
var myobjectprototype = new Object();
var myfunctionprototype = new Object();
myfunctionprototype.my__proto__ = myobjectprototype;
var myobject = new Object();
myobject.myprototype = myobjectprototype;
และอื่น ๆ คุณสามารถเติมส่วนที่เหลือของโปรแกรมเพื่อสร้างชุดของวัตถุที่มีโทโพโลยีเดียวกันกับวัตถุในตัว Javascript ที่ "จริง" ได้หรือไม่? ถ้าคุณทำเช่นนั้นคุณจะพบว่ามันง่ายมาก
วัตถุใน JavaScript มีตารางการค้นหาเพียงว่าสายเชื่อมโยงกับวัตถุอื่น แค่นั้นแหละ! ไม่มีเวทย์มนตร์ที่นี่ คุณกำลังผูกตัวเป็นปมเพราะคุณกำลังจินตนาการถึงข้อ จำกัด ที่ไม่มีอยู่จริงเช่นเดียวกับที่วัตถุทุกชิ้นจะต้องสร้างขึ้นโดยผู้สร้าง
ฟังก์ชั่นเป็นเพียงวัตถุที่มีความสามารถเพิ่มเติม: ถูกเรียก ดังนั้นให้ลองผ่านโปรแกรมจำลองสถานการณ์เล็ก ๆ ของคุณและเพิ่ม.mycallableคุณสมบัติให้กับทุกวัตถุที่ระบุว่าสามารถเรียกได้หรือไม่ มันง่ายอย่างนั้น
Function.prototypeสามารถเป็นฟังก์ชั่นและมีเขตข้อมูลภายใน ดังนั้นคุณจะไม่เรียกใช้ฟังก์ชันต้นแบบเมื่อผ่านโครงสร้าง ในที่สุดจำไว้ว่ามีการตีความเครื่องยนต์ Javascript ดังนั้นวัตถุและฟังก์ชั่นอาจถูกสร้างขึ้นภายในเครื่องยนต์และไม่ได้มาจาก Javascript และการอ้างอิงพิเศษเช่นFunction.prototypeและObject.prototypeอาจถูกตีความในลักษณะพิเศษโดยเครื่องยนต์