JavaScript
Advanced Concepts
Prototype & Inheritance
ทำความเข้าใจ prototype chain ของ JavaScript เรียนรู้ constructor function, Object.create, และ instanceof เพื่อสร้าง inheritance chain และ shared methods
ปัญหาที่ Prototype แก้ได้
สมมติเราสร้าง object หลายตัวที่มี method เหมือนกัน ถ้าสร้างแบบ object literal จะต้องซ้ำ method ทุก object นี่คือปัญหา: หน่วยความจำเปลือง และแก้โค้ดที่เดียวไม่ได้กระจายทุก object
// ปัญหา: method ซ้ำกันทุก object
const dog1 = { name: "Rex", speak() { return this.name + " พูดว่า woof"; } };
const dog2 = { name: "Buddy", speak() { return this.name + " พูดว่า woof"; } };
const dog3 = { name: "Max", speak() { return this.name + " พูดว่า woof"; } };
// dog1.speak, dog2.speak, dog3.speak เป็น function คนละชิ้น ทำงานเหมือนกัน
// แต่ใช้ memory แยกกัน 3 ก้อน — ไม่ดีเมื่อมีหลายพัน objectMental Model: สายสกุล
ลองนึกถึงสายสกุล: ลูก → พ่อ → ปู่ เมื่อถามลูกว่า "บ้านอยู่ที่ไหน?" ถ้าลูกตอบไม่ได้ จะถามพ่อต่อ ถ้าพ่อตอบไม่ได้ จะถามปู่ต่อ JavaScript ทำงานแบบเดียวกัน: เมื่อเข้าถึง property ที่ object ไม่มี JavaScript จะค้นหาต่อไปใน **prototype** ของ object นั้น → prototype ของ prototype → จนถึง null
Prototype Chain คืออะไร
ทุก object ใน JavaScript มี internal link ที่เรียกว่า `[[Prototype]]` ที่ชี้ไปยัง object อีกตัว (หรือ null) เมื่อ JavaScript ค้นหา property บน object แล้วไม่พบ มันจะไล่ขึ้น `[[Prototype]]` chain ไปเรื่อยๆ จนกว่าจะพบหรือถึง null
| คำศัพท์ | ความหมาย |
|---|---|
| [[Prototype]] | internal link ที่ทุก object มี ชี้ไปยัง prototype ของมัน |
| __proto__ | property ที่ใช้อ่าน/เขียน [[Prototype]] ได้ (เป็น legacy, ใช้ Object.getPrototypeOf แทนดีกว่า) |
| Constructor.prototype | object ที่ instance ที่สร้างด้วย new Constructor จะ inherit มาจาก |
| Object.create(proto) | สร้าง object ใหม่ที่มี proto เป็น prototype |
Constructor Function + prototype.method
รูปแบบคลาสสิกก่อน ES6 class syntax คือการใช้ "constructor function" (ฟังก์ชันที่เรียกด้วย `new`) และเพิ่ม method ลงใน `Constructor.prototype` Instance ทุกตัวจะ **share** method เดียวกันผ่าน prototype chain แทนที่จะมีสำเนาแยกกัน
// Constructor function (ตั้งชื่อ PascalCase ตามธรรมเนียม)
function Dog(name) {
this.name = name; // property เฉพาะของแต่ละ instance
}
// เพิ่ม method ลงบน prototype — ทุก instance ใช้ร่วมกัน
Dog.prototype.speak = function() {
return this.name + " พูดว่า woof";
};
const d1 = new Dog("Rex");
const d2 = new Dog("Buddy");
console.log(d1.speak()); // "Rex พูดว่า woof"
console.log(d2.speak()); // "Buddy พูดว่า woof"
// method เดียวกัน ใช้ร่วมกัน
console.log(d1.speak === d2.speak); // true ✓ (ไม่ซ้ำกัน)Object.create — กำหนด Prototype โดยตรง
`Object.create(proto)` สร้าง object ใหม่ที่มี `proto` เป็น prototype เป็นวิธีที่ชัดเจนในการสร้าง inheritance chain
const animal = {
breathe() {
return this.name + " หายใจ";
}
};
// สร้าง dog ที่มี animal เป็น prototype
const dog = Object.create(animal);
dog.name = "Rex";
dog.bark = function() {
return this.name + " เห่า";
};
console.log(dog.bark()); // "Rex เห่า" ← method ของตัวเอง
console.log(dog.breathe()); // "Rex หายใจ" ← ได้จาก prototype (animal)
// ตรวจสอบ chain
console.log(Object.getPrototypeOf(dog) === animal); // truePrototype Chain Lookup ทีละขั้น
เมื่อเขียน `obj.property` JavaScript ทำตามขั้นตอนนี้:
- ค้นหา property บน obj เอง — ถ้าพบ ใช้ค่านั้น
- ถ้าไม่พบ ไปดูที่ obj.[[Prototype]] (prototype ของ obj)
- ทำซ้ำขึ้นไปเรื่อยๆ ตาม chain
- ถ้าถึง null แล้วยังไม่พบ คืนค่า undefined
function Animal(name) { this.name = name; }
Animal.prototype.breathe = function() { return this.name + " หายใจ"; };
function Dog(name) {
Animal.call(this, name); // เรียก Animal constructor เพื่อ set this.name
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() { return this.name + " เห่า"; };
const rex = new Dog("Rex");
// Lookup chain: rex → Dog.prototype → Animal.prototype → Object.prototype → null
console.log(rex.name); // "Rex" ← ใน rex เอง
console.log(rex.bark()); // "Rex เห่า" ← ใน Dog.prototype
console.log(rex.breathe()); // "Rex หายใจ" ← ใน Animal.prototype
console.log(rex instanceof Dog); // true
console.log(rex instanceof Animal); // trueสรุป
- ทุก object มี [[Prototype]] link ที่ JavaScript ใช้ค้นหา property ที่ไม่มีบน object เอง
- Constructor function + prototype.method คือรูปแบบคลาสสิกสำหรับ shared methods
- Object.create(proto) สร้าง object ที่มี proto เป็น prototype โดยตรง
- instanceof ตรวจสอบว่า object อยู่ใน prototype chain ของ constructor หรือไม่
- ES6 class syntax (บทถัดไป) เป็น syntactic sugar บน prototype นี้เอง