在 JavaScript 中,__proto__
和 prototype
是兩個容易混淆但又至關重要的概念,它們都與原型鏈相關,但扮演著不同的角色。理解它們的區別對於理解 JavaScript 的繼承機制至關重要。
prototype
(原型物件)
- 定義:
prototype
屬性是函式物件才擁有的屬性。它指向一個物件,這個物件就是透過該函式建立的例項的原型。換句話說,當使用new
運算子建立一個新的物件時,新物件的__proto__
屬性會指向建構函式的prototype
屬性。 - 作用:
prototype
屬性用於定義透過建構函式建立的物件的共享屬性和方法。所有透過該建構函式建立的例項都共享同一個原型物件。這樣可以節省記憶體,並且方便地實現繼承。 - 例子:
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log("Hello, my name is " + this.name);
};
const person1 = new Person("Alice");
const person2 = new Person("Bob");
person1.greet(); // Output: Hello, my name is Alice
person2.greet(); // Output: Hello, my name is Bob
console.log(person1.greet === person2.greet); // Output: true (Both instances share the same greet function)
__proto__
(原型鏈指標)
- 定義:
__proto__
屬性是所有物件都擁有的屬性 (除了透過Object.create(null)
建立的物件)。它是一個內部屬性,指向建立該物件的建構函式的prototype
屬性。換句話說,它指向該物件的原型。 - 作用:
__proto__
屬性構成了 JavaScript 的原型鏈。當訪問一個物件的屬性時,JavaScript 引擎首先會在物件自身查詢該屬性。如果找不到,就會沿著__proto__
指向的原型物件繼續查詢,直到找到該屬性或者到達原型鏈的頂端 (null)。 - 例子: 在上面的例子中,
person1.__proto__
指向Person.prototype
。
關鍵區別總結:
特性 | prototype |
__proto__ |
---|---|---|
歸屬 | 函式物件 | 所有物件 (除Object.create(null) 建立的物件) |
作用 | 定義例項的原型 | 指向物件的原型 |
訪問方式 | 直接訪問 | 透過 Object.getPrototypeOf(obj) 或非標準的 obj.__proto__ 訪問 |
Object.getPrototypeOf()
推薦使用 Object.getPrototypeOf(obj)
來獲取物件的原型,因為它比 __proto__
更標準和更可靠。 __proto__
雖然在大多數現代瀏覽器中都受支援,但它並不是 ECMAScript 標準的一部分,並且在某些環境中可能不可用。
最佳實踐:
為了程式碼的可讀性和可維護性,建議使用現代 JavaScript 的 class 語法來定義類和繼承關係,它底層仍然是基於原型鏈的,但提供了更清晰的語法。
希望這個解釋能夠幫助你理解 __proto__
和 prototype
的區別。