深入解析 JavaScript 原型與原型鏈:從原理到應用

原型原型鏈是 JavaScript 中實現對象繼承和屬性查找的核心機制。為了更深入地理解它們,我們需要從底層原理、實現機制以及實際應用等多個角度進行分析。


1. 原型(Prototype)

1.1 什么是原型?

  • 每個 JavaScript 對象(除 null 外)都有一個內部屬性 [[Prototype]],指向它的原型對象。
  • 原型對象也是一個普通對象,它包含可以被其他對象共享的屬性和方法。
  • 通過 __proto__(非標準,但廣泛支持)或 Object.getPrototypeOf() 可以訪問對象的原型。

1.2 構造函數與原型

  • 每個函數(構造函數)都有一個 prototype 屬性,指向一個對象,這個對象是該構造函數實例的原型。
  • 當使用 new 關鍵字創建實例時,實例的 [[Prototype]] 會指向構造函數的 prototype 對象。
function Person(name) {this.name = name;
}// 在構造函數的原型上添加方法
Person.prototype.sayHello = function() {console.log(`Hello, my name is ${this.name}`);
};const person1 = new Person('Alice');
person1.sayHello(); // 輸出: Hello, my name is Alice
  • 在上面的例子中:
    • Person.prototypeperson1 的原型對象。
    • person1.__proto__ 指向 Person.prototype

2. 原型鏈(Prototype Chain)

2.1 什么是原型鏈?

  • 原型鏈是由對象的 [[Prototype]] 連接起來的鏈式結構。
  • 當訪問對象的屬性或方法時,如果對象本身沒有該屬性,JavaScript 會沿著原型鏈向上查找,直到找到該屬性或到達原型鏈的頂端(null)。

2.2 原型鏈的頂端

  • 所有對象的原型鏈最終都會指向 Object.prototype,而 Object.prototype[[Prototype]]null
  • 如果在整個原型鏈中都找不到屬性,則返回 undefined
console.log(person1.toString()); // 輸出: [object Object]
  • 在上面的例子中:
    • person1 本身沒有 toString 方法。
    • JavaScript 引擎會沿著原型鏈查找:
      1. person1 -> 沒有 toString
      2. person1.__proto__(即 Person.prototype) -> 沒有 toString
      3. Person.prototype.__proto__(即 Object.prototype) -> 找到 toString,調用它。

3. 原型鏈的深度分析

3.1 原型鏈的構建

  • 原型鏈是通過 [[Prototype]] 連接起來的。
  • 當我們創建一個對象時,它的 [[Prototype]] 會指向某個原型對象。
const obj = {};
console.log(obj.__proto__ === Object.prototype); // true
  • 如果我們手動修改 [[Prototype]],可以構建自定義的原型鏈。
const parent = { name: 'Parent' };
const child = Object.create(parent); // child.__proto__ 指向 parent
console.log(child.name); // 輸出: Parent

3.2 原型鏈的查找機制

  • 當訪問對象的屬性時,JavaScript 引擎會按照以下步驟查找:
    1. 檢查對象自身是否有該屬性。
    2. 如果沒有,沿著 [[Prototype]] 向上查找。
    3. 重復這個過程,直到找到屬性或到達 null
const grandparent = { familyName: 'Smith' };
const parent = Object.create(grandparent);
const child = Object.create(parent);console.log(child.familyName); // 輸出: Smith
  • 在上面的例子中:
    • child 自身沒有 familyName
    • child.__proto__(即 parent)也沒有 familyName
    • parent.__proto__(即 grandparent)有 familyName,返回 Smith

4. 原型鏈與繼承

4.1 基于原型的繼承

  • JavaScript 通過原型鏈實現繼承。
  • 子類的原型對象指向父類的實例,從而繼承父類的屬性和方法。
function Person(name) {this.name = name;
}Person.prototype.sayHello = function() {console.log(`Hello, my name is ${this.name}`);
};function Student(name, grade) {Person.call(this, name); // 調用父類構造函數this.grade = grade;
}// 繼承父類原型
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student; // 修復構造函數指向const student1 = new Student('Bob', 10);
student1.sayHello(); // 輸出: Hello, my name is Bob
  • 在上面的例子中:
    • Student.prototype 的原型指向 Person.prototype
    • student1 可以訪問 Person.prototype 上的方法。

4.2 原型鏈的局限性

  • 原型鏈繼承是單向的,子類可以訪問父類的屬性和方法,但父類不能訪問子類的屬性和方法。
  • 如果原型鏈過長,屬性查找的性能會受到影響。

5. 原型鏈的實際應用

5.1 共享方法

  • 將方法定義在原型上,可以避免每個實例都創建一份方法的副本,節省內存。
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 和 person2 共享同一個 sayHello 方法
console.log(person1.sayHello === person2.sayHello); // true

5.2 擴展內置對象

  • 可以通過修改內置對象的原型來擴展其功能。
Array.prototype.last = function() {return this[this.length - 1];
};const arr = [1, 2, 3];
console.log(arr.last()); // 輸出: 3

6. 總結

  • 原型:每個對象都有一個 [[Prototype]],指向它的原型對象。
  • 原型鏈:通過 [[Prototype]] 連接起來的鏈式結構,用于屬性查找。
  • 繼承:通過原型鏈實現對象之間的繼承。
  • 性能:原型鏈過長會影響查找性能,需謹慎設計。

理解原型和原型鏈是掌握 JavaScript 面向對象編程的關鍵,也是深入理解 JavaScript 運行機制的基礎。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/71834.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/71834.shtml
英文地址,請注明出處:http://en.pswp.cn/web/71834.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

FPGA時序約束的幾種方法

一,時鐘約束 時鐘約束是最基本的一個約束,因為FPGA工具是不知道你要跑多高的頻率的,你必要要告訴工具你要跑的時鐘頻率。時鐘約束也就是經常看到的Fmax,因為Fmax是針對“最差勁路徑”,也就是說,如果該“最差勁路徑”得到好成績,那些不是最差勁的路徑的成績當然比…

Visual Studio Code打開遠程服務器項目,打開服務器Android上百G源碼,SSH免密連接方式

Visual Studio Code打開遠程服務器項目 1,Visual Studio Code拓展中,安裝遠程插件 Remote Development 2,SSH免密連接,A電腦免密連接B,配置B電腦.ssh/authorized_keys A電腦的.ssh/id_rsa.pub中的公鑰內容,…

AWS云編排詳解-Cloud Formation

作者:私語茶館 1.關鍵概念 名詞 說明 軟件: CloudFormation 描述AWS 資源、配置值和互連關系。借助集成設施即代碼加快云部署 CloudFormation Designer 拖拽式圖形化模板編輯界面。 Amazon Simple Notification Service (SNS) SNS可通過電子郵件跟蹤堆棧的創建和刪除進度,…

《PyQt5》——設計Python GUI(圖形用戶界面)實例

PyQt5 PyQt5的配置和基礎使用可以參考這篇文章:《 PyQt5》—— 創建 Python GUI(圖形用戶界面) Python GUI(圖形用戶界面)實例 本實例是設計一個通過玉米和豆粕的價格來預測生豬的價格,并顯示預測價格與實…

kali linux 打開 word

Kali Linux是一款專為網絡安全領域而設計的操作系統,它集成了大量的安全工具,幫助用戶進行網絡滲透測試和安全評估。作為一款功能強大的操作系統,Kali Linux可以滿足用戶在網絡安全領域的各種需求,包括滲透測試、漏洞分析、數字取…

hooks useModule自定義hooks (二次封裝AgGridReact ag-table)自定義表頭,自定義表頭搜索

場景業務: 多次運用AgGridReact的table 列表 思路: 運用自定義hooks進行二次封裝: 通用配置例如:傳參的參數,傳參的url,需要緩存的key這些鍵值類 定制化配置例如:需要對table 的一些定制化傳…

SpringBoot最簡單方式實現自定義異常頁面(404)

最簡單的方式實現所有自定義異常頁面(如 404、500 等)是通過 靜態資源文件 或 模板引擎 來實現。 方法 1:使用靜態資源文件(最簡單) Spring Boot 默認會在 src/main/resources/static 或 src/main/resources/public …

django下防御race condition漏洞(競爭型漏洞)

目錄 競爭型漏洞 概念 常見類型及示例 環境搭建 ?編輯漏洞復現 ucenter/1/ ucenter/2/ ucenter/3/ ucenter/4/ 總結 悲觀鎖 樂觀鎖 競爭型漏洞 概念 競爭型漏洞,也稱為競態條件漏洞(Race Condition Vulnerability),…

用Python寫一個算24點的小程序

一、運行界面 二、顯示答案——遞歸介紹 工作流程&#xff1a; 1. 基本情況&#xff1a;函數首先檢查輸入的數字列表 nums 的長度。如果列表中只剩下一個數字&#xff0c;它會判斷這個數字是否接近 24&#xff08;使用 abs(nums[0] - 24) < 1e-10 來處理浮點數精度問題&…

PostgreSQL 18新特性之虛擬生成列

PostgreSQL 12 提供了生成列&#xff08;GENERATED ALWAYS AS STORED&#xff09;功能&#xff0c;但是只能支持存儲型的生成列&#xff0c;需要占用存儲空間&#xff0c;更新成本高。 為此&#xff0c;PostgreSQL 18 即將引入一個新的增強&#xff1a;虛擬生成列。這種類型的…

GitHub上傳項目

總結&#xff08;有基礎的話直接執行這幾步&#xff0c;就不需要再往下看了&#xff09;&#xff1a; git init 修改git的config文件&#xff1a;添加:[user]:name你的github用戶名 email你注冊github的用戶名 git branch -m master main git remote add origin 你的URL gi…

常見排序算法深度評測:從原理到10萬級數據實戰

常見排序算法深度評測&#xff1a;從原理到10萬級數據實戰 摘要 本文系統解析冒泡排序、選擇排序、插入排序、希爾排序、歸并排序、快速排序、堆排序和基數排序8種經典算法&#xff0c;通過C語言實現10萬隨機數排序并統計耗時。測試顯示&#xff1a;快速排序綜合性能最優&…

動態規劃填表技巧:固定最后一個數 vs 固定倒數第二個數

在動態規劃中&#xff0c;填表時固定最后一個數還是倒數第二個數&#xff0c;取決于問題的定義和狀態轉移方程的設計。 目錄 1. 固定最后一個數 適用場景 特點 示例 2. 固定倒數第二個數 適用場景 特點 示例 3. 固定最后一個數與倒數第二個數的對比 4. 總結 1. 固定最…

【C】鏈式二叉樹算法題2

目錄 1 另一棵樹的子樹 1&#xff09; 題目描述 示例1&#xff1a; 示例2&#xff1a; 2&#xff09; 算法解析 3&#xff09; 代碼 2 二叉樹的遍歷 1&#xff09; 問題描述 2&#xff09; 算法解析 3&#xff09; 代碼 3 總結 1 另一棵樹的子樹 leetcode鏈接…

配置Hadoop集群

Hadoop的運行模式 本地運行&#xff1a;在一臺單機上運行&#xff0c;沒有分布式文件系統&#xff0c;直接讀寫本地操作系統的文件系統。特點&#xff1a;不對配置文件進行修改&#xff0c;Hadoop 不會啟動 偽分布式&#xff1a;也是在一臺單機上運行&#xff0c;但用不同的 …

python辦公自動化--數據可視化(pandas+matplotlib)--生成條形圖和餅狀圖

前言 前幾天我們學習了pandas讀取數據&#xff0c;還學習了如何用patplotlib繪制柱狀圖和折線圖。 今天我們繼續學習&#xff0c;如何繪制條形圖和餅狀圖。 一、課程回顧-pandas讀取數據 1.示例數據文件 這里我們用到的依舊是d盤底下的這個excel工作簿&#xff0c;這個工作簿…

基于大模型的結節性甲狀腺腫診療全流程預測與方案研究報告

目錄 一、引言 1.1 研究背景與目的 1.2 研究意義 1.3 國內外研究現狀 二、大模型預測原理與方法 2.1 相關大模型概述 2.2 數據收集與預處理 2.3 模型訓練與驗證 三、術前預測與評估 3.1 結節性質預測 3.1.1 良惡性判斷 3.1.2 與傳統診斷方法對比 3.2 手術風險預測…

不同開發語言對字符串的操作

一、字符串的訪問 Objective-C: 使用 characterAtIndex: 方法訪問字符。 NSString *str "Hello, World!"; unichar character [str characterAtIndex:0]; // 訪問第一個字符 H NSLog("%C", character); // 輸出: H NSString 內部存儲的是 UTF-16 編…

Java開發者如何接入并使用DeepSeek

目錄 一、準備工作 二、添加DeepSeek SDK依賴 三、初始化DeepSeek客戶端 四、數據上傳與查詢 五、數據處理與分析 六、實際應用案例 七、總結 【博主推薦】&#xff1a;最近發現了一個超棒的人工智能學習網站&#xff0c;內容通俗易懂&#xff0c;風格風趣幽默&#xff…

S19文件格式詳解:汽車ECU軟件升級中的核心鏡像格式

文章目錄 引言一、S19文件格式的起源與概述二、S19文件的核心結構三、S19在汽車ECU升級中的應用場景四、S19與其他格式的對比五、S19文件實例解析六、工具鏈支持與安全考量七、未來趨勢與挑戰結語引言 在汽車電子控制單元(ECU)的軟件升級過程中,S19文件(也稱為Motorola S-…