《從分遺產說起:JS 原型與繼承詳解》

?

“天天開心就好”


先來講講概念:?

原型(Prototype)

什么是原型?

原型是 JavaScript 中實現對象間共享屬性和方法的機制。每個 JavaScript 對象(除了?null)都有一個內部鏈接指向另一個對象,這個對象就是它的"原型"(prototype)。

繼承(Inheritance)

什么是繼承?

繼承是面向對象編程中的一個核心概念,它允許一個對象(子對象)獲取另一個對象(父對象)的屬性和方法。在 JavaScript 中,繼承主要通過原型鏈來實現。

好的現在我們明確了什么是原型,什么是繼承。簡單來說,原型就是一個機制,每個對象內部都一個內部鏈接指向他的原型。繼承我的理解就是一種行為,就是像繼承財產那樣繼承父對象的屬性和方法,可謂是形容十分貼切。

原型基礎

原型對象 (prototype)

  • 每個函數都有一個?prototype?屬性(箭頭函數除外)
  • 這個屬性指向一個對象,稱為"原型對象"
  • 原型對象包含可以被特定類型的所有實例共享的屬性和方法
function Person() {}
Person.prototype.name = 'Default';
Person.prototype.sayHello = function() {console.log(`Hello, I'm ${this.name}`);
};

__proto__?屬性

  • 每個對象都有一個?__proto__?屬性(現已標準化為?Object.getPrototypeOf()
  • 指向創建該對象的構造函數的原型對象
const person = new Person();
console.log(person.__proto__ === Person.prototype); // true

這個很好理解了,我在這里想用c語言里面的指針來形容了。prototype就像是地址對應的數據,而_proto_就像是指向他的指針。不太恰當哈

?我們經常這樣說:對象的繼承是通過原型鏈實現的。

那么什么是原型鏈:

什么是原型鏈?

原型鏈(Prototype Chain)是 JavaScript 中實現繼承的核心機制。當訪問一個對象的屬性或方法時,JavaScript 引擎會沿著對象的原型鏈向上查找,直到找到該屬性或到達原型鏈的末端(null)。

原型鏈的構成

  1. ??每個對象都有一個?__proto__?屬性??(現已標準化為?Object.getPrototypeOf()
  2. ??每個函數都有一個?prototype?屬性??
  3. ??原型鏈的終點是?null??

原型鏈的工作原理

當訪問一個對象的屬性時:

  1. 首先在對象自身查找該屬性
  2. 如果沒有找到,則查找對象的?__proto__(即其構造函數的?prototype
  3. 如果還沒有找到,繼續查找?__proto__.__proto__,依此類推
  4. 直到找到該屬性或到達?null(此時返回?undefined
function Animal(name) {this.name = name;
}
Animal.prototype.eat = function() {console.log(`${this.name} is eating`);
};function Dog(name, breed) {Animal.call(this, name);this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {console.log('Woof!');
};const myDog = new Dog('Buddy', 'Golden Retriever');// 原型鏈:
// myDog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null

我們講原型和繼承就是在意js中繼承這種行為是怎么實現的,就像現實中大家只在乎怎么分遺產一樣!

繼承實現方式

?1.原型鏈繼承

function Parent() {this.parentProperty = true;
}
Parent.prototype.getParentValue = function() {return this.parentProperty;
};function Child() {this.childProperty = false;
}
// 繼承 Parent
Child.prototype = new Parent();const instance = new Child();
console.log(instance.getParentValue()); // true

??問題??:

  • 所有子類實例共享同一個父類實例
  • 無法向父類構造函數傳參

2. 構造函數繼承

function Parent(name) {this.name = name;
}function Child(name) {Parent.call(this, name); // 在子類構造函數中調用父類構造函數
}const child = new Child('Alice');
console.log(child.name); // 'Alice'

??優點??:

  • 可以向父類傳參
  • 每個子類實例都有獨立的父類屬性副本

??缺點??:

  • 無法繼承父類原型上的方法

3.組合繼承(最常用)

function Parent(name) {this.name = name;
}
Parent.prototype.sayName = function() {console.log(this.name);
};function Child(name, age) {Parent.call(this, name); // 第二次調用 Parentthis.age = age;
}
Child.prototype = new Parent(); // 第一次調用 Parent
Child.prototype.constructor = Child; // 修復構造函數指向const child = new Child('Alice', 25);
child.sayName(); // 'Alice'

??優點??:

  • 結合了原型鏈和構造函數的優點
  • 既能繼承原型方法,又能保證實例屬性獨立

??缺點??:

  • 父類構造函數被調用了兩次

4. 原型式繼承

function object(o) {function F() {}F.prototype = o;return new F();
}const parent = { name: 'Parent' };
const child = object(parent);
console.log(child.name); // 'Parent'

ES5 標準化為?Object.create()

const child = Object.create(parent);

5. 寄生式繼承

function createAnother(original) {const clone = Object.create(original);clone.sayHi = function() {console.log('Hi');};return clone;
}

6. 寄生組合式繼承(最佳實踐)

function inheritPrototype(child, parent) {const prototype = Object.create(parent.prototype);prototype.constructor = child;child.prototype = prototype;
}function Parent(name) {this.name = name;
}
Parent.prototype.sayName = function() {console.log(this.name);
};function Child(name, age) {Parent.call(this, name);this.age = age;
}inheritPrototype(Child, Parent);const child = new Child('Alice', 25);
child.sayName(); // 'Alice'

??優點??:

  • 只調用一次父類構造函數
  • 原型鏈保持正確
  • 最理想的繼承方式

ES6 的 class 繼承

class Parent {constructor(name) {this.name = name;}sayName() {console.log(this.name);}
}class Child extends Parent {constructor(name, age) {super(name); // 調用父類構造函數this.age = age;}
}const child = new Child('Alice', 25);
child.sayName(); // 'Alice'

??注意??:

  • class?本質上是語法糖,底層仍然是基于原型的繼承
  • extends?實現了寄生組合式繼承
  • 必須在使用?this?前調用?super()

繼承是js中很核心的機制了,有很多中方式來實現繼承,繼承的好處就是我們可以直接繼承父對象的方法和屬性而不用自己再次定義了。用好繼承可以大大提升我們的代碼水平,幫助我們實現更多復雜需求。?


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

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

相關文章

立馬耀:通過阿里云 Serverless Spark 和 Milvus 構建高效向量檢索系統,驅動個性化推薦業務

作者:廈門立馬耀網絡科技有限公司大數據開發工程師 陳宏毅 背景介紹 行業 蟬選是蟬媽媽出品的達人選品服務平臺。蟬選秉持“陪伴達人賺到錢”的品牌使命,致力于洞悉達人變現需求和痛點,提供達人選高傭、穩變現、速響應的選品服務。 業務特…

Android顯示學習筆記本

根據博客 Android-View 繪制原理(01)-JAVA層分析_android view draw原理分析-CSDN博客 提出了我的疑問 Canvas RenderNode updateDisplayListDirty 這些東西的關系 您的理解在基本方向上是對的,但讓我詳細解釋一下 Android 中 updateDisplayListDirty、指令集合、…

JavaWeb學習打卡-Day4-會話技術、JWT、Filter、Interceptor

會話技術 會話:用戶打開瀏覽器,訪問web服務器的資源,會話建立,直到有一方斷開連接,會話結束。在一次會話中可以包含多次請求和響應。會話跟蹤:一種維護瀏覽器狀態的方法,服務器需要識別多次請求…

讓數據優雅落地:用 serde::Deserialize 玩轉結構體實體

前言 想象一下,服務器突然飛來一堆 JSON 數據,就像一群無頭蒼蠅沖進辦公室,嗡嗡作響,橫沖直撞。此刻,你的任務,就是把這群“迷路數據”安置進正確的格子里,分門別類,秩序井然,不混不亂,不漏一只。 好在 Rust 早就為我們備好瑞士軍刀:serde::Deserialize。它不僅刀…

Virtio 技術解析 | 框架、設備實現與實踐指南

本文為 “Virtio” 相關文章合輯。 略作重排,如有內容異常,請看原文。 Virtio 簡介(一)—— 框架分析 posted 2021-04-21 10:14 Edver 1. 概述 在傳統設備模擬中,虛擬機內部設備驅動完全不知自身處于虛擬化環境&a…

云計算賦能質檢LIMS的價值 質檢LIMS系統在云計算企業的創新應用

在云計算技術高速發展的背景下,實驗室信息化管理正經歷深刻變革。質檢LIMS(實驗室信息管理系統)作為實驗室數字化轉型的核心工具,通過與云計算深度融合,為企業提供了高彈性、高安全性的解決方案。本文將探討質檢LIMS在…

【win11 安裝WSL2 詳解一遍過!!】

共有五個步驟,按部就班的做,保準成功! 1. 打開開發者模式 設置->系統->開發者模式 2. 打開linux的win子系統 找到控制面板-程序和功能-啟用或關閉Windows功能,選中“適用于Linux的Windows子系統”,“虛擬機…

Godot開發2D冒險游戲——第三節:游戲地圖繪制

一、初步構建游戲地圖 在游戲場景當中添加一個新的子節點:TileMapLayer 這一層稱為瓦片地圖層 根據提示,下一步顯然是添加資源 為TileMapLayer節點添加一個TileSet 將地板添加進來,然后選擇自動分割圖集 自定義時要確保大小合適 讓Godot自…

Django創建的應用目錄詳細解釋以及如何操作數據庫自動創建表

創建好Django項目后 如果要創建 python manage.py startapp 模塊名模塊 使用 我創建一個system模塊后是 注意:urls是我自己建的文件 1.migrations目錄 存放數據庫的遷移文件,當models.py中模型定義發生變化時,通過遷移操作能同步數據庫結構變化 __init__ 使該目錄…

將輸入幀上下文打包到下一個幀的預測模型中用于視頻生成

Paper Title: Packing Input Frame Context in Next-Frame Prediction Models for Video Generation 論文發布于2025年4月17日 Abstract部分 在這篇論文中,FramePack是一種新提出的網絡結構,旨在解決視頻生成中的兩個主要問題:遺忘和漂移。 具體來說,遺忘指的是在生成視…

STM32 串口USART

目錄 常見的通信方式 串行通信和并行通信 全雙工,半雙工和單工通信 同步通信和異步通信 通信速率 常見的通信協議 串口基礎知識 電平特性 串口傳輸協議 STM32F103的USART資源 端口引腳 數據寄存器單元 發送接收控制單元 實現串口發送 printf…

Taro on Harmony :助力業務高效開發純血鴻蒙應用

背景 純血鴻蒙逐漸成為全球第三大操作系統,業界也掀起了適配鴻蒙原生的浪潮,用戶遷移趨勢明顯,京東作為國民應用,為鴻蒙用戶提供完整的購物體驗至關重要。   去年 9 月,京東 AP…

gem5-gpu教程05 內存建模

memory-modeling|Details on how memory is modeled in gem5-gpu gem5-gpu’s Memory Simulation gem5-gpu在很大程度上避開了GPGPU-Sim的單獨功能模擬,而是使用了gem5的執行中執行模型。因此,當執行存儲/加載時,內存會被更新/讀取。沒有單獨的功能路徑。(順便說一句,這…

【python】lambda用法(結合例子理解)

目錄 lambda 是什么? 為什么叫 lambda? 語法 舉例 1. 最簡單的 lambda:單個數字處理 2. 用 lambda 排序一組字符串(按照長度排序) 3. 在列表里找出絕對值最小的數字 4. 給 map() 用 lambda 5. 組合使用:篩選出偶數 lambda 和 def 的對比 lambda 適合用在什么地…

【ROS2】機器人操作系統安裝到Ubuntu22.04簡介(手動)

主要參考: https://book.guyuehome.com/ROS2/1.系統架構/1.3_ROS2安裝方法/ 官方文檔:https://docs.ros.org/en/humble/Installation.html 虛擬機與ubuntu系統安裝 略,見參考文檔 ubutun換國內源,略 1. 設置本地語言 確保您有…

C 調用 C++:extern “C” 接口詳解與實踐 C/C++混合編譯

C 調用 C:extern “C” 接口詳解與實踐 核心問題在于 C 編譯器會對函數名進行“修飾”(Name Mangling)以支持函數重載等特性,而 C 編譯器則不會。此外,C 語言本身沒有類、對象等概念。為了解決這個問題,我…

汽車制造行業如何在數字化轉型中抓住機遇?

近年來,隨著新一輪科技革命和產業變革的深入推進,汽車制造行業正迎來一場前所未有的數字化轉型浪潮。無論是傳統車企還是新勢力品牌,都在積極探索如何通過數字化技術提升競爭力、開拓新市場。那么,在這場變革中,汽車制…

k8s學習記錄(五):Pod親和性詳解

一、前言 上一篇文章初步探討了 Kubernetes 的節點親和性,了解到它在 Pod 調度上比傳統方式更靈活高效。今天我們繼續討論親和性同時Kubernetes 的調度機制。 二、Pod親和性 上一篇文章中我們介紹了節點親和性,今天我們講解一下Pod親和性。首先我們先看…

HarmonyOS:Navigation實現導航之頁面設置和路由操作

導讀 設置標題欄模式設置菜單欄設置工具欄路由操作頁面跳轉頁面返回頁面替換頁面刪除移動頁面參數獲取路由攔截 子頁面頁面顯示類型頁面生命周期頁面監聽和查詢 頁面轉場關閉轉場自定義轉場共享元素轉場 跨包動態路由系統路由表自定義路由表 示例代碼 Navigation組件適用于模塊…

雪花算法

目錄 一、什么是雪花算法 二、使用雪花算法 ?三、使用UUID 使用自增主鍵是數據庫中常用的唯一標識,今天嘗試使用mybatisplus來實現三種方式的主鍵ID 使用起來也很簡單 用注解指定一下使用那種方式的主鍵 一、什么是雪花算法 一種特殊的算法可以計算得到一個唯…