高級前端工程師必備的 JS 設計模式入門教程,常用設計模式案例分享

目錄

高級前端工程師必備的 JS 設計模式入門教程,常用設計模式案例分享

一、什么是設計模式?為什么前端也要學?

1、設計模式是什么

2、設計模式的產出

二、設計模式在 JS 里的分類

三、常用設計模式實戰講解

1、單例模式(Singleton)

2、工廠模式(Factory)

3、觀察者模式(Observer)

4、代理模式(Proxy)

5、策略模式(Strategy)

6、建造者模式、適配器模式、裝飾器模式和狀態模式

①建造者模式(Builder Pattern)

②適配器模式(Adapter Pattern)

③裝飾器模式(Decorator Pattern)

④狀態模式(State Pattern)

四、結語


????????作者:watermelo37

? ? ? ? CSDN萬粉博主、華為云云享專家、阿里云專家博主、騰訊云、支付寶合作作者,全平臺博客昵稱watermelo37。

? ? ? ? 一個假裝是giser的coder,做不只專注于業務邏輯的前端工程師,Java、Docker、Python、LLM均有涉獵。

---------------------------------------------------------------------

溫柔地對待溫柔的人,包容的三觀就是最大的溫柔。

---------------------------------------------------------------------

高級前端工程師必備的 JS 設計模式入門教程,常用設計模式案例分享

本文適合有JavaScript基礎 、?Vue/React 開發經驗,但對設計模式不太熟悉的前端開發工程師。

????????什么是設計模式?為什么要有設計模式?單例模式、工廠模式、建造者模式、適配器模式、代理模式、裝飾器模式、觀察者模式、策略模式、狀態模式分別是什么?他們解決了什么樣的問題?本文將給您答案。

一、什么是設計模式?為什么前端也要學?

1、設計模式是什么

????????設計模式,就是程序員們總結出來的一套解決常見代碼問題的方法論

  • 它不是死板的規定,不是必須按部就班執行。

  • 它是經驗總結,告訴你在遇到某些類型的問題時,如何寫出更優雅、更健壯、更可擴展的代碼。

  • 后端用,前端也用,尤其是當你的項目越來越大、多人協作越來越復雜時,設計模式就越重要。

????????類比一下:設計模式就像打游戲時的「固定套路」,讓你在遇到不同怪物時不用每次重頭想招數,而是有一套拿得出手的打法。

2、設計模式的產出

????????設計模式的產出不是特定代碼片段,而是一套可復用的設計思路或結構

  • 有些模式產出一個「結構」(比如單例產出一個唯一對象)。

  • 有些模式產出一個「流程/機制」(比如觀察者產出的是發布-訂閱機制)。

  • 也有些是組合型的,既有對象也有通信邏輯。

????????設計模式產出的是「結構 + 行為」的組合,沒有嚴格固定形式,但背后有固定的“意圖”或“問題場景”。我們關注的就是其“意圖”和“場景”。

二、設計模式在 JS 里的分類

????????設計模式很多,但最重要的,可以分成三大類:

類型解釋代表模式
創建型解決「如何創建對象」的問題單例模式、工廠模式、建造者模式
結構型解決「對象之間怎么組織結構」的問題適配器模式、代理模式、裝飾器模式
行為型解決「對象之間怎么協作通信」的問題觀察者模式、策略模式、狀態模式

三、常用設計模式實戰講解

1、單例模式(Singleton)

? ? ? ? 定義:整個系統只存在一個實例對象,并且能全局訪問。

? ? ? ? 舉個例子,Vuex里面的store就是單例,事件總線(Event Bus)也是單例。

? ? ? ? 來做個簡單的實現,它通過一個靜態屬性 instance 儲存實例,并在重復創建時返回已有實例,這樣就能實現單例的效果:

class Store {constructor() {if (Store.instance) {return Store.instance;}this.state = {};Store.instance = this;}
}const a = new Store();
const b = new Store();console.log(a === b); // true

2、工廠模式(Factory)

? ? ? ? 定義:用一個函數/類專門負責創建對象,不直接用 new。

? ? ? ? 舉幾個例子,組件封裝:根據類型不同返回不同組件實例還有 Axios 的實例化都是工廠模式。

? ? ? ? 工廠模式的優勢在于能統一創建邏輯,并且拓展非常方便,各類型之間高內聚,低耦合。做個簡單的實現:

function createButton(type) {if (type === 'primary') {return { color: 'blue', size: 'large' };} else if (type === 'danger') {return { color: 'red', size: 'large' };}
}const btn = createButton('primary');
console.log(btn); // { color: 'blue', size: 'large' }

工廠函數是什么??

????????工廠函數(Factory Function)是一個普通函數,它封裝了創建對象的過程,并返回這個對象。它是實現工廠模式的一種方式,但不限于工廠模式使用。

function createPerson(name, age) {return {name,age,sayHello() {console.log(`Hi, I'm ${name}`);}}
}const person = createPerson('Tom', 20);

? ? ? ? 這個案例中的 createPerson 就是工廠函數。

3、觀察者模式(Observer)

? ? ? ? 定義:一對多關系,一個對象變化,通知所有依賴它的對象。

? ? ? ??比如Vue 響應式,發布訂閱(EventEmitter)都屬于觀察者模式。

? ? ? ? 一般情況下,觀察者模式里面一定有一個叫做 notify / emit / publish 或類似功能的函數,用來通知所有的訂閱者,這種函數本質上就是廣播機制,是觀察者模式的核心實現函數。做個簡單的案例:維護一組回調,變化時循環觸發。

class Observer {constructor() {this.subscribers = [];}subscribe(fn) {this.subscribers.push(fn);}notify(data) {this.subscribers.forEach(fn => fn(data));}
}const obs = new Observer();obs.subscribe((data) => console.log('收到1', data));
obs.subscribe((data) => console.log('收到2', data));obs.notify('你好');
// 收到1 你好
// 收到2 你好

4、代理模式(Proxy)

? ? ? ? 定義:通過一個代理對象控制對目標對象的訪問。

? ? ? ? Vue3的響應式Proxy、接口請求封裝都屬于代理模式。

? ? ? ? 先用Proxy舉例:

const target = {name: '張三'
};const proxy = new Proxy(target, {get(obj, prop) {console.log(`訪問屬性:${prop}`);return obj[prop];},set(obj, prop, value) {console.log(`設置屬性:${prop}=${value}`);obj[prop] = value;return true;}
});proxy.name; // 訪問屬性:name
proxy.age = 20; // 設置屬性:age=20

? ? ? ? 這個例子比較常見,是不是意猶未盡?我們再來一個圖片懶加載的代理模式來舉例:

// 真正加載圖片的方法
function loadImage(src) {const img = new Image();img.src = src;document.body.appendChild(img);
}// 創建一個代理來控制圖片加載
const proxyImage = (function () {let img = new Image();img.onload = function() {loadImage(this.src); // 真正加載}return function(src) {// 先用一張 loading 圖片占位loadImage('loading.jpg');// 真正的圖片異步加載完成后替換img.src = src;}
})();// 使用
proxyImage('real-image.jpg');

????????proxyImage 函數就是代理對象,loadImage是被代理的目標對象,用戶一調用它就顯示 loading 圖,真正圖片在加載完畢后替換。

????????這里使用 IIFE(立即執行函數表達式) 是為了創建一次性的私有作用域和閉包,隔離 img 變量,避免污染。

????????執行邏輯為:

  1. 代碼剛執行時,生成了一個 proxyImage 函數,這個函數內部封裝了一個私有的 Image 對象 img,并且給 img.onload 綁定了回調函數。

  2. 調用 proxyImage(src) 時,先 loadImage('loading.jpg') 顯示一個占位圖,再設置 img.src = src(真實圖片地址)。

  3. 這時瀏覽器會開始異步加載 src 指向的真實圖片,這一步是靜默執行的,DOM渲染的是默認圖片。

  4. 加載完畢后自動觸發 img.onload,在回調里重新調用 loadImage(this.src),替換成真實圖。

? ? ? ? 其中,默認圖片(loading.jpg)應該是一個極小的圖,通過base64編碼內嵌到代碼里,或者直接用svg小圖標,如果是個大一點的圖片應該讓瀏覽器預加載,以此來實現用戶視角下的默認圖片無感渲染。

5、策略模式(Strategy)

? ? ? ? 定義:將一系列算法封裝成獨立的策略類,使它們可以互相替換。

? ? ? ??比如一些表單驗證、支付方式切換過程等。

? ? ? ? 其優勢在于具有開閉原則(增加新策略不用改老代碼),并且代碼可擴展。舉例如下,其中strategies 里是具體的策略集合(算法實現),validate 是「上下文」調用器(根據情況選擇策略執行),兩者配合才構成完整的策略模式實現:

const strategies = {isNonEmpty(value) {return value !== '';},minLength(value, length) {return value.length >= length;}
};function validate(value, rule, ...args) {return strategies[rule](value, ...args);
}console.log(validate('abc', 'minLength', 2)); // true

開閉原則:

????????即對擴展開放,對修改關閉。

? ? ? ? 產生新需求時,應該通過新增代碼來實現,而不是修改現有代碼。這樣可以減少出錯的風險,提高系統的穩定性。

? ? ? ? 在策略模式中,策略模式增加新策略,只是添加新策略對象,不需要去改 validate 函數本體

? ? ? ? 有沒有覺得策略模式和工廠模式很像?都是通過一個“judge info”(type與rule)來判斷到底該如何執行。但他們存在以下區別:

策略模式工廠模式
關注執行邏輯不同關注對象創建不同
替換算法/規則替換對象
運行時切換生成時選擇

6、建造者模式、適配器模式、裝飾器模式和狀態模式

????????這四個相對少見,簡單介紹:

①建造者模式(Builder Pattern)

????????分步驟構建一個復雜對象,而不是一口氣構造。比如建一臺電腦:

class ComputerBuilder {constructor() {this.computer = {};}addCPU(cpu) {this.computer.cpu = cpu;return this;}addRAM(ram) {this.computer.ram = ram;return this;}addStorage(storage) {this.computer.storage = storage;return this;}build() {return this.computer;}
}const myComputer = new ComputerBuilder().addCPU('Intel i9').addRAM('32GB').addStorage('1TB SSD').build();
②適配器模式(Adapter Pattern)

????????讓原本接口不兼容的兩個類可以一起工作。比如一個老版 API 返回的是 snake_case,但新系統要求 camelCase:

function oldApi() {return { user_name: 'Tom', user_age: 20 };
}// 適配器
function adapterApi() {const data = oldApi();return {userName: data.user_name,userAge: data.user_age};
}const result = adapterApi();
③裝飾器模式(Decorator Pattern)

????????在不修改原對象的情況下,動態增加功能。比如增強 log 函數(這里相當于額外打印了時間):

function log(msg) {console.log(msg);
}// 裝飾器
function withTimestamp(fn) {return function(...args) {console.log(`[${new Date().toISOString()}]`);return fn(...args);}
}const decoratedLog = withTimestamp(log);
decoratedLog('Hello World');
④狀態模式(State Pattern)

????????對象內部狀態不同,行為也不同。比如電燈開關:

class Light {constructor() {this.state = 'off';}toggle() {if (this.state === 'off') {console.log('Turning on');this.state = 'on';} else {console.log('Turning off');this.state = 'off';}}
}const light = new Light();
light.toggle(); // Turning on
light.toggle(); // Turning off

四、結語

????????設計模式能讓人寫出更穩定、可維護的代碼,JavaScript中最常用的設計模式有單例、工廠、觀察者、代理、策略五種。學設計模式就相當于學解決復雜問題的套路,在框架中,如 Vue / React項目里,幾乎隨處可見設計模式的身影。

????????只有鍛煉思維才能可持續地解決問題,只有思維才是真正值得學習和分享的核心要素。如果這篇博客能給您帶來一點幫助,麻煩您點個贊支持一下,還可以收藏起來以備不時之需,有疑問和錯誤歡迎在評論區指出~

????????其他熱門文章,請關注:

? ? ? ??極致的靈活度滿足工程美學:用Vue Flow繪制一個完美流程圖

???? ? ?你真的會使用Vue3的onMounted鉤子函數嗎?Vue3中onMounted的用法詳解

????????DeepSeek:全棧開發者視角下的AI革命者

??? ? ??通過array.filter()實現數組的數據篩選、數據清洗和鏈式調用

??? ? ??通過Array.sort() 實現多字段排序、排序穩定性、隨機排序洗牌算法、優化排序性能

??? ? ??TreeSize:免費的磁盤清理與管理神器,解決C盤爆滿的燃眉之急

??? ? ??通過MongoDB Atlas 實現語義搜索與 RAG——邁向AI的搜索機制

???? ? ?深入理解 JavaScript 中的 Array.find() 方法:原理、性能優勢與實用案例詳解

???? ? ?el-table實現動態數據的實時排序,一篇文章講清楚elementui的表格排序功能

??? ? ??MutationObserver詳解+案例——深入理解 JavaScript 中的 MutationObserver

????????JavaScript中通過array.map()實現數據轉換、創建派生數組、異步數據流處理、DOM操作等

????????前端實戰:基于Vue3與免費滿血版DeepSeek實現無限滾動+懶加載+瀑布流模塊及優化策略

????????高效工作流:用Mermaid繪制你的專屬流程圖;如何在Vue3中導入mermaid繪制流程圖

????????干貨含源碼!如何用Java后端操作Docker(命令行篇)

????????在線編程實現!如何在Java后端通過DockerClient操作Docker生成python環境

??? ? ??Dockerfile全面指南:從基礎到進階,掌握容器化構建的核心工具

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

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

相關文章

Ubuntu+Docker+內網穿透:保姆級教程實現安卓開發環境遠程部署

文章目錄 前言1. 虛擬化環境檢查2. Android 模擬器部署3. Ubuntu安裝Cpolar4. 配置公網地址5. 遠程訪問小結 6. 固定Cpolar公網地址7. 固定地址訪問 前言 本文將詳細介紹一種創新性的云開發架構:基于Ubuntu系統構建Android仿真容器環境,并集成安全隧道技…

Linux Kernel調試:強大的printk(一)

引言 想了好久,還是覺得這個標題才配得上printk!^_^ 我相信,不管做什么開發,使用最多的調試手段應該就是打印了,從我們學習編程語言第一課開始,寫的第一段代碼,就是打印"Hello, world&qu…

基于NLP技術的客戶投訴與需求文本分類方法研究

目錄 摘要 1. 引言 2. 文本分類基礎 2.1 文本分類的定義與類型 2.2 文本分類的評價指標 3. 傳統文本分類方法 3.1 基于TF-IDF和SVM的方法 3.2 基于主題模型和詞向量的改進方法 4. 深度學習文本分類方法 4.1 TextCNN模型 4.2 BiLSTM模型 4.3 注意力機制與Transformer…

#RabbitMQ# 消息隊列入門

目錄 一 MQ技術選型 1 運行rabbitmq 2 基本介紹 3 快速入門 1 交換機負責路由消息給隊列 2 數據隔離 二 Java客戶端 1 快速入門 2 WorkQueue 3 FanOut交換機 4 Direct交換機 5 Topic交換機 *6 聲明隊列交換機 1 在配置類當中聲明 2 使用注解的方式指定 7 消息轉…

【深度學習】多目標融合算法(六):漸進式分層提取模型PLE(Progressive Layered Extraction)

目錄 一、引言 二、PLE(Progressive Layered Extraction,漸進式分層提取模型) 2.1 技術原理 2.2 技術優缺點 2.3 業務代碼實踐 2.3.1 業務場景與建模 2.3.2 模型代碼實現 2.3.3 模型訓練與推理測試 2.3.4 打印模型結構 三、總結 一…

【Java開發日記】如何使用Java開發在線生成 pdf 文檔

一、介紹 在實際的業務開發的時候,研發人員往往會碰到很多這樣的一些場景,需要提供相關的電子憑證信息給用戶,例如網銀/支付寶/微信購物支付的電子發票、訂單的庫存打印單、各種電子簽署合同等等,以方便用…

Oracle 11g 單實例使用+asm修改主機名導致ORA-29701 故障分析

解決 把服務器名修改為原來的,重啟服務器。 故障 建表空間失敗。 分析 查看告警日志 ORA-1119 signalled during: create tablespace splex datafile ‘DATA’ size 2000M… Tue May 20 18:04:28 2025 create tablespace splex datafile ‘DATA/option/dataf…

消息隊列的使用

使用內存隊列來處理基于內存的【生產者-消費者】場景 思考和使用Disruptor Disruptor可以實現單個或多個生產者生產消息,單個或多個消費者消息,且消費者之間可以存在消費消息的依賴關系 使用Disruptor需要結合業務特性,設計要靈活 什么業務…

《帝國時代1》游戲秘籍

資源類 PEPPERONI PIZZA:獲得 1000 食物。COINAGE:獲得 1000 金。WOODSTOCK:獲得 1000 木頭。QUARRY:獲得 1000 石頭。 建筑與生產類 STEROIDS:快速建筑。 地圖類 REVEAL MAP:顯示所有地圖。NO FOG&#xf…

使用JSP踩過的坑

雖然說jsp已經過時了,但是有時維護比較老的項目還是需要的。 下面說下,我使用jsp踩過的坑: 1.關于打印輸出 在jsp中輸出使用 out.println("hello");而不是 System.out.println("hello");如果在定義函數部分需要打印…

redis集群創建時手動指定主從關系的方法

適用場景: 創建主從關系時默認參數 --cluster-replicas 1 會自動分配從節點。 為了能精確控制 Redis Cluster 的主從拓撲結構,我們通過 Redis Cluster 的手動分片功能來實現 一、手動指定主從關系的方法 使用 redis-cli --cluster-replicas 0 先創建純…

ROS合集(七)SVIn2聲吶模塊分析

文章目錄 一、整體思想二、具體誤差建模流程三、總結明確(預測值與觀測值)四、選點邏輯五、Sonar 數據處理流水線1. ROS Launch 配置(imagenex831l.launch)2. SonarNode 節點(sonar_node.py)3. Subscriber …

Python爬蟲實戰:研究PySpider框架相關技術

1. 引言 1.1 研究背景與意義 網絡爬蟲作為互聯網數據采集的重要工具,在信息檢索、輿情分析、市場調研等領域發揮著重要作用。隨著互聯網信息的爆炸式增長,如何高效、穩定地獲取所需數據成為了一個關鍵挑戰。PySpider 作為一款功能強大的 Python 爬蟲框架,提供了豐富的功能…

《大模型開源與閉源的深度博弈:科技新生態下的權衡與抉擇》

開源智能體大模型的核心魅力,在于它構建起了一個全球開發者共同參與的超級協作網絡。想象一下,來自世界各個角落的開發者、研究者,無論身處繁華都市還是偏遠小鎮,只要心懷對技術的熱愛與追求,就能加入到這場技術狂歡中…

大數據模型對陌生場景圖像的識別能力研究 —— 以 DEEPSEEK 私有化部署模型為例

摘要 本研究聚焦于已訓練的大數據模型能否識別未包含在樣本數據集中的陌生場景圖像這一問題,以 DEEPSEEK 私有化部署模型為研究對象,結合機器學習理論,分析模型識別陌生場景圖像的影響因素,并通過理論探討與實際應用場景分析&…

STM32——從點燈到傳感器控制

STM32基礎外設開發:從點燈到傳感器控制 一、前言 本篇文章總結STM32F10x系列基礎外設開發實例,涵蓋GPIO控制、按鍵檢測、傳感器應用等。所有代碼基于標準庫開發,適合STM32初學者參考。 二、硬件準備 STM32F10x系列開發板LED模塊有源蜂鳴器…

[特殊字符] 使用增量同步+MQ機制將用戶數據同步到Elasticsearch

在開發用戶搜索功能時,我們通常會將用戶信息存儲到 Elasticsearch(簡稱 ES) 中,以提高搜索效率。本篇文章將詳細介紹我們是如何實現 MySQL 到 Elasticsearch 的增量同步,以及如何通過 MQ 消息隊列實現用戶信息實時更新…

MyBatis緩存機制全解析

在MyBatis中,緩存分為一級緩存和二級緩存,它們的主要目的是減少數據庫的訪問次數,提高查詢效率。下面簡述這兩種緩存的工作原理: 一、 一級緩存(SqlSession級別的緩存) 一級緩存是MyBatis默認開啟的緩存機…

【短距離通信】【WiFi】WiFi7關鍵技術之4096-QAM、MRU

目錄 3. 4096-QAM 3.1 4096-QAM 3.2 QAM 的階數越高越好嗎? 4. MRU 4.1 OFDMA 和 RU 4.2 MRU 資源分配 3. 4096-QAM 摘要 本章主要介紹了Wi-Fi 7引入的4096-QAM對數據傳輸速率的提升。 3.1 4096-QAM 對速率的提升 Wi-Fi 標準一直致力于提升數據傳輸速率&a…

【二刷力扣】【力扣熱題100】今天的題目是:283.移動零

題目: 給定一個數組 nums,編寫一個函數將所有 0 移動到數組的末尾,同時保持非零元素的相對順序。 請注意 ,必須在不復制數組的情況下原地對數組進行操作。 示例 1: 輸入: nums [0,1,0,3,12] 輸出: [1,3,12,0,0] 示例 2: 輸…