본문으로 건너뛰기

เนื้อหาภาษาไทย / 태국어 콘텐츠

시스템 가이드 검수 완료된 콘텐츠

Prototype Inheritance

บทความนี้อธิบายถึง Prototype Inheritance ซึ่งเป็นกลไกหลักที่ JavaScript ใช้ในการจำลองแนวคิด Object-Oriented Programming (OOP) โดย object สามารถสืบทอดคุณสมบัติจา...

Prototype Inheritance ใน JavaScript: สืบทอดคุณสมบัติอย่างเข้าใจง่าย

จากบทที่แล้วที่เราได้เรียนรู้เกี่ยวกับ Revealing Module Pattern ซึ่งเน้นเรื่องการจัดการ scope และ encapsulation ใน JavaScript คราวนี้เราจะมาเจาะลึกอีกหนึ่ง concept ที่สำคัญไม่แพ้กัน นั่นคือ Prototype Inheritance หรือการสืบทอดคุณสมบัติผ่าน Prototype ซึ่งเป็นกลไกหลักที่ทำให้ JavaScript สามารถจำลองแนวคิด Object-Oriented Programming (OOP) ได้อย่างมีประสิทธิภาพ

Prototype Inheritance คือกลไกที่ object สามารถสืบทอดคุณสมบัติ (properties และ methods) จาก object อื่นได้ โดย object ที่ถูกสืบทอดเรียกว่า "prototype" และ object ที่สืบทอดเรียกว่า "instance" หรือ "object" นั่นเอง การสืบทอดนี้เกิดขึ้นผ่านสิ่งที่เรียกว่า Prototype Chain ซึ่งเราจะอธิบายในรายละเอียดต่อไป

Prototype Chain คืออะไร?

Prototype Chain เปรียบเสมือนห่วงโซ่ที่เชื่อมต่อ object ต่างๆ เข้าด้วยกัน โดยแต่ละ object จะมี link ไปยัง prototype ของมัน หากเราพยายามเข้าถึง property หรือ method ที่ object นั้นไม่มี JavaScript จะทำการค้นหาใน prototype ของ object นั้น และถ้ายังไม่พบก็จะค้นหาใน prototype ของ prototype ไปเรื่อยๆ จนกว่าจะพบ property หรือ method ที่ต้องการ หรือจนกว่าจะถึงจุดสิ้นสุดของ chain ซึ่งก็คือ null

ลองพิจารณาตัวอย่างต่อไปนี้:

function Animal(name) {
  this.name = name;
}

Animal.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.name);
};

function Dog(name, breed) {
  Animal.call(this, name); // เรียก constructor ของ Animal เพื่อกำหนด name
  this.breed = breed;
}

// กำหนด prototype ของ Dog ให้เป็น instance ของ Animal
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // สำคัญ: กำหนด constructor กลับเป็น Dog

Dog.prototype.bark = function() {
  console.log("Woof!");
};

const myDog = new Dog("Buddy", "Golden Retriever");

myDog.sayHello(); // Output: Hello, I'm Buddy (สืบทอดมาจาก Animal)
myDog.bark();    // Output: Woof! (มาจาก Dog เอง)

console.log(myDog.name);  // Output: Buddy (มาจาก Animal)
console.log(myDog.breed); // Output: Golden Retriever (มาจาก Dog)

console.log(myDog instanceof Animal); // Output: true
console.log(myDog instanceof Dog);    // Output: true

ในตัวอย่างนี้:

  • เราสร้าง constructor function ชื่อ Animal ซึ่งมี property name และ method sayHello
  • เราสร้าง constructor function ชื่อ Dog ซึ่งสืบทอดจาก Animal โดยใช้ Animal.call(this, name) เพื่อเรียก constructor ของ Animal และกำหนด property breed เพิ่มเติม
  • ที่สำคัญที่สุด เรากำหนด Dog.prototype ให้เป็น instance ของ Animal.prototype โดยใช้ Object.create(Animal.prototype) ซึ่งเป็นการสร้าง object ใหม่ที่มี prototype เป็น Animal.prototype
  • เรากำหนด Dog.prototype.constructor = Dog; เพื่อให้ constructor ของ Dog.prototype ชี้กลับไปยัง Dog ซึ่งเป็นสิ่งสำคัญเพื่อให้ instanceof ทำงานได้อย่างถูกต้อง
  • เราเพิ่ม method bark ให้กับ Dog.prototype

เมื่อเราสร้าง instance myDog จาก Dog, myDog จะสามารถเข้าถึง property name และ method sayHello ได้เนื่องจากสืบทอดมาจาก Animal นอกจากนี้ยังสามารถเข้าถึง property breed และ method bark ที่เป็นของ Dog เองได้อีกด้วย

__proto__ property

ทุก object ใน JavaScript (ยกเว้น object ที่สร้างขึ้นโดย Object.create(null)) จะมี property พิเศษชื่อ __proto__ (double underscore proto double underscore) ซึ่งชี้ไปยัง prototype ของ object นั้น แม้ว่า __proto__ จะเป็น property ที่ไม่แนะนำให้ใช้ใน production code (เนื่องจากเป็น non-standard และอาจถูกเปลี่ยนแปลงในอนาคต) แต่การทำความเข้าใจการทำงานของมันจะช่วยให้เราเข้าใจ Prototype Chain ได้ดียิ่งขึ้น

ในตัวอย่างก่อนหน้า:

  • myDog.__proto__ จะชี้ไปยัง Dog.prototype
  • Dog.prototype.__proto__ จะชี้ไปยัง Animal.prototype
  • Animal.prototype.__proto__ จะชี้ไปยัง Object.prototype
  • Object.prototype.__proto__ จะเป็น null ซึ่งเป็นจุดสิ้นสุดของ Prototype Chain

ดังนั้นเมื่อเราพยายามเข้าถึง property หรือ method ที่ myDog ไม่มี JavaScript จะทำการค้นหาใน Dog.prototype จากนั้น Animal.prototype และสุดท้าย Object.prototype ตามลำดับ

Object.create()

Object.create() เป็น method ที่ใช้สร้าง object ใหม่ที่มี prototype เป็น object ที่เรากำหนด วิธีนี้เป็นวิธีที่แนะนำให้ใช้ในการสร้าง object ที่สืบทอดมาจาก object อื่น เนื่องจากมีความยืดหยุ่นและปลอดภัยกว่าการแก้ไข prototype โดยตรง

Syntax: Object.create(proto, [propertiesObject])

  • proto: object ที่จะเป็น prototype ของ object ใหม่
  • propertiesObject (optional): object ที่กำหนด properties และ descriptors ของ object ใหม่

ตัวอย่างการใช้งาน Object.create():

const person = {
  name: "John",
  sayHello: function() {
    console.log("Hello, my name is " + this.name);
  }
};

const student = Object.create(person);
student.name = "Alice";
student.major = "Computer Science";

student.sayHello(); // Output: Hello, my name is Alice (สืบทอดมาจาก person)
console.log(student.major); // Output: Computer Science (มาจาก student เอง)

console.log(student.__proto__ === person); // Output: true

ในตัวอย่างนี้ student สืบทอด properties และ methods จาก person และเราสามารถเพิ่ม properties ใหม่ให้กับ student ได้โดยไม่กระทบกับ person

กรณีใช้งานจริงและข้อผิดพลาดที่พบบ่อย

Prototype Inheritance ถูกนำไปใช้อย่างแพร่หลายในการพัฒนา JavaScript Libraries และ Frameworks ต่างๆ เพื่อสร้าง component ที่สามารถนำกลับมาใช้ใหม่ได้ ตัวอย่างเช่น React, Angular, และ Vue.js ใช้ Prototype Inheritance เพื่อสร้าง component classes ที่สามารถสืบทอดคุณสมบัติและ methods จากกันและกันได้

ข้อผิดพลาดที่พบบ่อย:

  • ลืมกำหนด Dog.prototype.constructor = Dog;: การลืมกำหนด constructor จะทำให้ instanceof ทำงานไม่ถูกต้อง และอาจทำให้เกิดปัญหาในการ debug
  • แก้ไข prototype โดยตรง: การแก้ไข prototype โดยตรงอาจส่งผลกระทบต่อ object ที่สร้างขึ้นแล้ว ดังนั้นควรใช้ Object.create() แทน
  • เข้าใจผิดว่า Prototype Inheritance คือ Class Inheritance: แม้ว่า Prototype Inheritance จะสามารถจำลองแนวคิด OOP ได้ แต่ก็มีความแตกต่างจาก Class Inheritance ในภาษาอื่นๆ เช่น Java หรือ C#

สรุป

Prototype Inheritance เป็นกลไกที่สำคัญในการทำความเข้าใจ JavaScript และเป็นพื้นฐานสำหรับ Object-Oriented Programming ใน JavaScript การเข้าใจ Prototype Chain และการใช้งาน Object.create() จะช่วยให้เราเขียนโค้ดที่ยืดหยุ่นและนำกลับมาใช้ใหม่ได้ง่ายขึ้น ในบทต่อไปเราจะมาเรียนรู้เกี่ยวกับ Class Syntax ซึ่งเป็น syntax ใหม่ที่ทำให้การเขียน OOP ใน JavaScript ง่ายขึ้นและคล้ายกับภาษาอื่นๆ มากขึ้น

Office.in.th Custom Service

이 구조를 바탕으로 시스템을 개발하거나 맞춤 변경하고 싶으신가요?

Office.in.th는 엔터프라이즈 웹 애플리케이션, API 연동, 공공/민간 업무 관리 시스템을 설계·개발하며 장기 지원을 제공합니다.

소프트웨어 개발 서비스 보기