在 JavaScript 中,原型和原型鏈是理解繼承和物件建立機制的核心概念。它們緊密聯絡,共同構成了 JavaScript 的物件導向特性。
1. 原型 (Prototype):
- 每個 JavaScript 函式都有一個
prototype
屬性,它是一個物件,被稱為函式的原型物件。 - 當一個函式被用作建構函式(使用
new
關鍵字)建立新物件時,新建立的物件會自動獲得一個內部的[[Prototype]]
屬性(在瀏覽器中可以透過__proto__
訪問,但__proto__
已被棄用,建議使用Object.getPrototypeOf()
),該屬性指向建構函式的prototype
屬性。 - 原型物件的主要作用是共享屬性和方法。透過原型,多個物件可以共享相同的屬性和方法,而無需在每個物件上單獨建立副本,從而節省記憶體。
2. 原型鏈 (Prototype Chain):
- 當訪問一個物件的屬性時,JavaScript 引擎首先會在物件自身查詢該屬性。
- 如果物件自身沒有該屬性,引擎會沿著原型鏈向上查詢。原型鏈是由物件的
[[Prototype]]
屬性連線起來的一系列物件。 - 查詢過程會一直持續到找到該屬性或者到達原型鏈的頂端 (null)。
- 原型鏈的頂端是
null
,這意味著如果在整個原型鏈上都沒有找到該屬性,則返回undefined
。
3. 原型和原型鏈的關係:
- 建構函式的
prototype
屬性決定了由該建構函式建立的物件的原型。 - 物件的
[[Prototype]]
屬性指向其建構函式的prototype
屬性,從而形成了原型鏈。 - 原型鏈本質上是一個連結串列結構,連線著物件及其原型,最終連線到
null
。
示例:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.name);
};
const person1 = new Person("Alice");
const person2 = new Person("Bob");
person1.sayHello(); // Output: Hello, my name is Alice
person2.sayHello(); // Output: Hello, my name is Bob
console.log(person1.hasOwnProperty("name")); // Output: true (name 屬性在 person1 物件自身)
console.log(person1.hasOwnProperty("sayHello")); // Output: false (sayHello 屬性在 Person.prototype 上)
console.log(Object.getPrototypeOf(person1) === Person.prototype); // Output: true (person1 的原型是 Person.prototype)
console.log(Object.getPrototypeOf(Person.prototype) === Object.prototype); // Output: true (Person.prototype 的原型是 Object.prototype)
console.log(Object.getPrototypeOf(Object.prototype) === null); // Output: true (Object.prototype 的原型是 null,原型鏈的頂端)
總結:
原型和原型鏈是 JavaScript 實現繼承和共享屬性的關鍵機制。理解它們的工作原理對於理解 JavaScript 的物件導向特性至關重要。 透過原型鏈,物件可以繼承來自其原型的屬性和方法,從而避免了程式碼冗餘,提高了程式碼的可重用性和效率。
希望這個解釋能夠幫助你理解 JavaScript 的原型和原型鏈。