JS學習筆記#25 | 原型(Prototype)與原型鏈

koko-avatar-img
發佈於JS學習
更新於 發佈於 閱讀時間約 7 分鐘

一、簡介

  • 什麼是原型?
    每個建構函數都有 prototype 屬性,是一個物件,用來存放共享的方法或屬性。
  • 什麼是原型鏈?
    物件透過 __proto__ 連接到其原型,形成屬性和方法的查找路徑。


二、原型的基本運作

function Person(name, age) {

this.name = name;

this.age = age;

}

Person.prototype.sayHi = function() {

console.log(`Hi, I'm ${this.name}`);

};

const p1 = new Person("Alice", 25);

const p2 = new Person("Bob", 30);

p1.sayHi(); // "Hi, I'm Alice"

p2.sayHi(); // "Hi, I'm Bob"

console.log(p1.sayHi === p2.sayHi); // true(共用同一個方法)

記憶體優勢

如果每個實例都帶一個 sayHi 函數,會浪費記憶體,因為這些函數功能相同,只是 this 不同,而將方法定義在 Person.prototype 上,所有實例共享,就能節省記憶體。

  • 未優化時:p1p2 各有一份 sayHi,佔用不同記憶體位置(p1.sayHi !== p2.sayHi)。
  • 優化後:sayHi 只有一份,實例仍獨立,但方法共享。


三、原型鏈

new 創建實例時,實例的 __proto__ 內部屬性會自動設為建構函數的 prototype,形成查找鏈。

const p = new Person("Alice");

console.log(p.__proto__ === Person.prototype); // true

console.log(p.hasOwnProperty("sayHi")); // false(不在 p 自身)

console.log(p instanceof Person); // true

原型鏈結構

p.__proto__ -> Person.prototype

Person.prototype.__proto__-> Object.prototype

Object.prototype.__proto__-> null



查找過程:

訪問屬性或方法時,從實例自身開始,沿原型鏈向上查找。

1.p 是什麼?

p 是用 new Person("Alice") 創建的實例。

2.p.__proto__ 是什麼?

__proto__ 是每個物件都有的內部屬性,指向它的「原型」。

當你用 new Person 創建 p 時,JavaScript 自動設定:

p.__proto__ = Person.prototype

3.Person.prototype 是什麼?

它是 Person 建構函數的一個屬性,預設是個物件。

4.Person.prototype.__proto__ 是什麼?

Person.prototype 本身也是一個物件,所以它也有自己的 __proto__。

因為它是普通物件,它的 __proto__ 指向 Object.prototype

5.Object.prototype 是什麼?

它是 JavaScript 中所有物件的「老祖宗」,包含一些基本方法(如 toString、hasOwnProperty)。

預設由 Object 建構函數提供。

6.Object.prototype.__proto__ 是什麼?

Object.prototype 是鏈的頂端,它的 __proto__ 是 null。

表示「沒有更上面的原型了」,查找就停在這裡。


四、原型能放什麼?

prototype 既可以定義方法,也可以定義屬性,實例都能透過原型鏈繼承。

Person.prototype.species = "Human"; // 原型上的屬性

console.log(p1.species); // "Human"(從原型繼承)

console.log(p2.species); // "Human"

console.log(p1.species === p2.species); // true(共享)

為什麼較少用來放屬性?

原型上的屬性是共享的,若修改可能影響所有實例,不適合個別化的資料。

若屬性需個別值(如 name),應放實例自身。



五、繼承

function Animal(name) {
this.name = name;
}
Animal.prototype.eat = function() {
console.log(`${this.name} is eating`);
};

function Dog(name) {
this.name = name;
}
Dog.prototype = new Animal(); // 繼承:把 Dog 的原型設為 Animal 的實例
Dog.prototype.bark = function() {
console.log(`${this.name} says woof`);
};

const dog = new Dog("Max");
dog.eat(); // "Max is eating"(從 Animal 繼承)
dog.bark(); // "Max says woof"(Dog 自己的)

// 驗證
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true

步驟解析

  1. 父類 Animal:定義 name 屬性和 eat 方法。
  2. 子類 Dog:設置 Dog.prototype = new Animal(),讓 Dog 的原型變成一個 Animal 實例。
  3. 創建 dog:new Dog("Max") 生成實例,dog 有自己的 name。

原型鏈

dog.__proto__ -> Dog.prototypenew Animal() 的實例)Dog.prototype.__proto__ -> Animal.prototype

Animal.prototype.__proto__ -> Object.prototype


六、注意事項

1.屬性遮蔽:實例上的同名屬性會覆蓋原型上的屬性。

dog.eat = function() {
console.log("Dog-specific eating");
};
dog.eat(); // "Dog-specific eating"(遮蔽原型)


2.避免循環引用:確保原型鏈不會無限循環。例如: 若誤設循環引用(如 A.prototype.__proto__ = A),查找會無限循環。


留言
avatar-img
留言分享你的想法!
avatar-img
koko的沙龍
1會員
34內容數
koko的沙龍的其他內容
2025/03/11
在 JavaScript 中,函數是物件,因此它們有內建方法可以用來控制執行方式。 這些方法包括 .call()、.apply() 和 .bind(),主要用來改變函數執行時的 this 指向或傳遞參數,特別在物件導向或繼承中很有用。
Thumbnail
2025/03/11
在 JavaScript 中,函數是物件,因此它們有內建方法可以用來控制執行方式。 這些方法包括 .call()、.apply() 和 .bind(),主要用來改變函數執行時的 this 指向或傳遞參數,特別在物件導向或繼承中很有用。
Thumbnail
2025/03/09
建構函數是 JavaScript 中用來創建和初始化物件的一種特殊函數。它像一個「模具」,透過 new 關鍵字生成多個相似的物件實例。
Thumbnail
2025/03/09
建構函數是 JavaScript 中用來創建和初始化物件的一種特殊函數。它像一個「模具」,透過 new 關鍵字生成多個相似的物件實例。
Thumbnail
2025/03/01
遞迴是指一個函數自己呼叫自己,用來解決可以分解成相似小問題的大問題。它就像一層層深入,最後再一層層回來的過程。
Thumbnail
2025/03/01
遞迴是指一個函數自己呼叫自己,用來解決可以分解成相似小問題的大問題。它就像一層層深入,最後再一層層回來的過程。
Thumbnail
看更多
你可能也想看
Thumbnail
沙龍一直是創作與交流的重要空間,這次 vocus 全面改版了沙龍介面,就是為了讓好內容被好好看見! 你可以自由編排你的沙龍首頁版位,新版手機介面也讓每位訪客都能更快找到感興趣的內容、成為你的支持者。 改版完成後可以在社群媒體分享新版面,並標記 @vocus.official⁠ ♥️ ⁠
Thumbnail
沙龍一直是創作與交流的重要空間,這次 vocus 全面改版了沙龍介面,就是為了讓好內容被好好看見! 你可以自由編排你的沙龍首頁版位,新版手機介面也讓每位訪客都能更快找到感興趣的內容、成為你的支持者。 改版完成後可以在社群媒體分享新版面,並標記 @vocus.official⁠ ♥️ ⁠
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
每年4月、5月都是最多稅要繳的月份,當然大部份的人都是有機會繳到「綜合所得稅」,只是相當相當多人還不知道,原來繳給政府的稅!可以透過一些有活動的銀行信用卡或電子支付來繳,從繳費中賺一點點小確幸!就是賺個1%~2%大家也是很開心的,因為你們把沒回饋變成有回饋,就是用卡的最高境界 所得稅線上申報
Thumbnail
在 TypeScript 中,套件是模組化代碼的集合,可以提高代碼的可重用性和可維護性。常見的套件包括各種庫和框架,如 lodash、express 等。以下是有關引用套件、自定義套件和常見套件的詳細介紹。
Thumbnail
在 TypeScript 中,套件是模組化代碼的集合,可以提高代碼的可重用性和可維護性。常見的套件包括各種庫和框架,如 lodash、express 等。以下是有關引用套件、自定義套件和常見套件的詳細介紹。
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
自訂元件生成位置顧名思義就是可以指定部分HTML區塊渲染在特定的畫面上,即使在不同組件也能把A組件內的部分畫面,展現在B組件上,以下方程式舉例。
Thumbnail
自訂元件生成位置顧名思義就是可以指定部分HTML區塊渲染在特定的畫面上,即使在不同組件也能把A組件內的部分畫面,展現在B組件上,以下方程式舉例。
Thumbnail
這些章節的目的是為了介紹JavaScript中的各種數據類型,包括基礎類型和物件類型,以及如何將數據從一種類型轉換為另一種類型。此外,還介紹了如何創建自定義類型,以及如何使用JavaScript中的陣列、集合和字典。
Thumbnail
這些章節的目的是為了介紹JavaScript中的各種數據類型,包括基礎類型和物件類型,以及如何將數據從一種類型轉換為另一種類型。此外,還介紹了如何創建自定義類型,以及如何使用JavaScript中的陣列、集合和字典。
Thumbnail
JavaScript是一種具有動態型別、弱型別、原型繼承等特性的高級腳本語言,應用範圍廣泛,包括前端開發、後端開發、移動應用等。它被各種公司和開源社區廣泛使用。學習JavaScript需要掌握ECMAScript標準、異步編程、模塊系統等知識。
Thumbnail
JavaScript是一種具有動態型別、弱型別、原型繼承等特性的高級腳本語言,應用範圍廣泛,包括前端開發、後端開發、移動應用等。它被各種公司和開源社區廣泛使用。學習JavaScript需要掌握ECMAScript標準、異步編程、模塊系統等知識。
Thumbnail
CSS 的繼承性是開發網頁樣式時的一個重要概念,它使得樣式設計更加靈活和高效,有助於提高程式碼的可讀性、一致性和可重用性,並加快開發速度,從而提供更好的開發體驗。
Thumbnail
CSS 的繼承性是開發網頁樣式時的一個重要概念,它使得樣式設計更加靈活和高效,有助於提高程式碼的可讀性、一致性和可重用性,並加快開發速度,從而提供更好的開發體驗。
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
前言 現在的前端需求已經越來越高,要考慮HTML及CSS的切版美觀程度,以及React以及Flutter所提出的元件(Componet、widget)觀念,也就是將元件模組化,使元件可以更動態的被程式運行,而不用靜態的客製化每一個介面。開發一個好的元件可以提升整體的開發速度,讓任何使用元件的開發者
Thumbnail
前言 現在的前端需求已經越來越高,要考慮HTML及CSS的切版美觀程度,以及React以及Flutter所提出的元件(Componet、widget)觀念,也就是將元件模組化,使元件可以更動態的被程式運行,而不用靜態的客製化每一個介面。開發一個好的元件可以提升整體的開發速度,讓任何使用元件的開發者
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News