Vue響應式原理六:Vue3響應式原理

1. 多個對象響應式

    1. 當前存在的問題:當前實現僅針對某個固定對象(obj)進行依賴收集,實際開發中需要處理多個不同對象
    1. 將對象響應式處理邏輯抽取為通用函數,支持任意對象
    1. 代碼如下:
         // 方案一:Object.defineProperty  -> Vue2// 多個對象響應式抽取成通用函數function reactive(obj) {Object.keys(obj).forEach(key => {let value = obj[key];Object.defineProperty(obj, key, {set: function(newValue) {value = newValue;const dep = getDepend(obj, key)dep.notify()},get: function() {// 找到對應的obj對象的key對應的dep對象const dep = getDepend(obj, key)// dep.addDepend(reactiveFn)dep.depend()return value;}})})return obj}
      
    1. Vue2實現:
    • 基于Object.defineProperty的響應式系統
    • data返回的對象會被reactive包裹處理
    • 模板編譯生成的render函數自動收集依賴

2. Vue3響應式原理(監聽對象-Proxy)

  • 2.1. 核心:使用Proxy替代Vue2的Object.defineProperty實現響應式

  • 2.2 與Vue2對比:

    • Vue2需要遍歷對象所有屬性進行監聽,Vue3Proxy可以自動監聽整個對象
    • Proxy能捕獲更多操作類型(如新增屬性、刪除屬性等)
  • 2.3. 完整代碼:

    // 方案二:new Proxy()  -> Vue3 
    function reactive(obj) {const objProxy = new Proxy(obj, {// receiver作用:1. 可以改變操作中的this指向 2. 確保getter/setter中的this指向代理對象set: function(target, key, newValue, receive) {// target[key] = newValueReflect.set(target, key, newValue, receive)const dep = getDepend(target, key)dep.notify()},get: function (target, key, receive) {const dep = getDepend(target, key)dep.depend()return Reflect.get(target, key, receive)}})return objProxy
    }
    

3. Depend類的重構

    1. 重構的點:
    • 使用Set替代數組存儲依賴函數,避免重復收集
    • 添加depend方法專門處理依賴收集邏輯
    1. 代碼如下:
        class Depend {constructor() {// 使用Set替代數組存儲依賴函數,避免重復收集this.reactiveFns = new Set();}addDepend (fn) {if(fn) {this.reactiveFns.add(fn);}}depend () {if(reactiveFn) {this.reactiveFns.add(reactiveFn)}}notify () {this.reactiveFns.forEach(fn => {fn()})}}

4. 完整代碼如下:


class Depend {constructor() {// 使用Set替代數組存儲依賴函數,避免重復收集this.reactiveFns = new Set();}addDepend (fn) {if(fn) {this.reactiveFns.add(fn);}}depend () {if(reactiveFn) {this.reactiveFns.add(reactiveFn)}}notify () {this.reactiveFns.forEach(fn => {fn()})}
}// 封裝一個函數:負責通過obj的key獲取對應的Depend對象
const objMap = new WeakMap() // WeakMap弱引用
function getDepend (obj, key) {// 1.根據對象obj,找到對應的map對象let map = objMap.get(obj)if(!map) {map = new Map()objMap.set(obj, map)}// 2.根據key,找到對應的depend對象let dep = map.get(key)if(!dep) {dep = new Depend();map.set(key, dep)}return dep
}// 監聽屬性變化數據劫持
// 方案一:Object.defineProperty  -> Vue2
// 多個對象響應式抽取成通用函數
// function reactive(obj) {
//   Object.keys(obj).forEach(key => {
//     let value = obj[key];
//     Object.defineProperty(obj, key, {
//       set: function(newValue) {
//         value = newValue;
//         const dep = getDepend(obj, key)
//         dep.notify()
//       },
//       get: function() {
//         // 找到對應的obj對象的key對應的dep對象
//         const dep = getDepend(obj, key)
//         // dep.addDepend(reactiveFn)
//         dep.depend()
//         return value;
//       }
//     })
//   })
//   return obj
// }// 方案二:new Proxy()  -> Vue3 
function reactive(obj) {const objProxy = new Proxy(obj, {// receiver作用:1. 可以改變操作中的this指向 2. 確保getter/setter中的this指向代理對象set: function(target, key, newValue, receive) {// target[key] = newValueReflect.set(target, key, newValue, receive)const dep = getDepend(target, key)dep.notify()},get: function (target, key, receive) {const dep = getDepend(target, key)dep.depend()return Reflect.get(target, key, receive)}})return objProxy
}// 設置一個專門執行響應式函數的一個函數
let reactiveFn = null // 自由變量
function watchFn (fn) {reactiveFn = fnfn()reactiveFn = null 
}//  =================================== 業務代碼 =====================================
const obj = reactive({name: 'why',age: 18,address: '長沙市'
})watchFn(function () {console.log(obj.name);console.log(obj.age);
})// 修改obj的屬性
console.log('age發生變化時----------------------------------------');
obj.age = 21console.log('user對象----------------------------------------');const user = reactive({nickName: 'abc',level: 100
})watchFn(function () {console.log('nickName: ' ,user.nickName);console.log('level: ' ,user.level);
})user.nickName = 'cba'

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

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

相關文章

【算法筆記 day three】滑動窗口(其他類型)

hello大家好!這份筆記包含的題目類型主要包括求子數組已經一些比較‘小眾’的題目。和之前一樣,筆記中的代碼和思路要么是我手搓要么是我借鑒一些大佬的想法轉化成自己的話復現。所以方法不一定是最好的,但一定是經過我理解的產物&#xff0c…

docker-鏡像管理指南

在本節中,我們將詳細介紹 Docker 鏡像的常用命令,幫助您更好地管理和操作鏡像。以下是核心命令及其功能說明:1.使用"ls"查看鏡像列表#查看現有的鏡像列表[rootdocker01 ~]# docker images [rootdocker01 ~]# docker image ls#僅查看…

Mac 電腦無法讀取硬盤的解決方案

引言近年來,選擇使用 Mac 電腦的用戶越來越多,尤其是在設計、開發、剪輯、文檔處理等領域,macOS 憑借其優秀的系統生態與硬件體驗吸引了大量擁躉。與此同時,對于攝影師、剪輯師、程序員、學生等用戶來說,一塊移動硬盤往…

25春期末考

web 瘋狂星期四 先來看一下源碼 分析代碼的黑名單后得知 我們可以用的字符就只剩下 字母a-z(大小寫均可) 數字2 空格 這里的限制太多了 這里比較常用的getallheaders被ban掉了 這里就是用session來做 session_start()開啟session session_id()獲取session 這里我們要構造一…

時間顯示 藍橋云課Java

目錄 題目鏈接 題目 解題思路 代碼 題目鏈接 競賽中心 - 藍橋云課 題目 解題思路 通過%天數,得到一天內的時間,然后/小時單位(換算成毫秒的)得到小時,然后總數減去該小時,得到分鐘數,秒數同理 代碼 import java.util.Scanner; // 1:無需package // 2: 類名必須Main, 不…

STM32F1控制步進電機

一、基礎知識1. 步進電機控制方式脈沖方向控制(最常見)控制信號:DIR方向:高低電平決定正轉或反轉;STEP脈沖:每個脈沖電機前進一步(可通過端口拉高拉低來模擬脈沖,或使用pwm來生成脈沖…

Docker 容器部署腳本

#!/bin/bash# # Author: ldj # Date: 2025-07-08 15:37:11 # Description: 首先刪除舊的容器和鏡像,然后登錄到 Harbor 并拉取最新的鏡像進行部署 # # 顯示每條命令執行情況,便于調試 set -x harbor_addr$1 harbor_repo$2 project_name$3 version$4 po…

OpenCV 4.10.0 移植 - Android

前文: Ubuntu 編譯 OpenCV SDK for Android Linux OpenCV 4.10.0 移植 概述 在移動應用開發領域,Android平臺與OpenCV庫的結合為開發者提供了強大的圖像處理和計算機視覺能力。OpenCV(Open Source Computer Vision Library)是一個開源的計算機視覺和機器學習軟件…

go go go 出發咯 - go web開發入門系列(二) Gin 框架實戰指南

go go go 出發咯 - go web開發入門系列(二) Gin 框架實戰指南 往期回顧 go go go 出發咯 - go web開發入門系列(一) helloworld 前言 前一節我們使用了go語言簡單的通過net/http搭建了go web服務,但是僅使用 Go 的標…

編譯OpenHarmony-4.0-Release RK3566 報錯

編譯OpenHarmony-4.0-Release RK3566 報錯1. 報錯問題2.問題解決3.解決方案4.?調試技巧?subsystem name config incorrect in ‘/home/openharmony/OpenHarmony/vendor/kaihong/khdvk_356b/bundle.json’, build file subsystem name is kaihong_products,configured subsy1.…

【PTA數據結構 | C語言版】線性表循環右移

本專欄持續輸出數據結構題目集,歡迎訂閱。 文章目錄題目代碼題目 給定順序表 A(a1?,a2?,?,an?),請設計一個時間和空間上盡可能高效的算法將該線性表循環右移指定的 m 位。例如,(1,2,5,7,3,4,6,8) 循環右移 3 位(m3) 后的結果…

c++-內部類

概念如果一個類定義在另一個類的內部,這個內部類就叫做內部類。內部類是一個獨立的類, 它不屬于外部類。特性1.不能通過外部類的對象去訪問內部類的成員。外部類對內部類沒有任何優越的訪問權限。 2.內部類就是外部類的友元類,參見友元類的定…

.golangci.yml文件配置

version: “2” run: timeout: 5m concurrency: 10 modules-download-mode: readonly linters: default: standard enable: - revive - cyclop settings: staticcheck: initialisms: [ “ACL”, “API”, “ASCII”, “CPU”, “CSS”, “DNS”, “EOF”, “GUID”, “HTML”, …

YOLO模型魔改指南:從原理到實戰,替換Backbone、Neck和Head(戰損版)

前言 Hello,大家好,我是GISer Liu😁,一名熱愛AI技術的GIS開發者。本系列是作者參加DataWhale 2025年6月份Yolo原理組隊學習的技術筆記文檔,這里整理為博客,希望能幫助Yolo的開發者少走彎路! &am…

Swift 圖論實戰:DFS 算法解鎖 LeetCode 323 連通分量個數

文章目錄摘要描述示例題解答案DFS 遍歷每個連通區域Union-Find(并查集)題解代碼分析(Swift 實現:DFS)題解代碼詳解構建鄰接表DFS 深度優先搜索遍歷所有節點示例測試及結果示例 1示例 2示例 3時間復雜度分析空間復雜度分…

【劍指offer】棧 隊列

📁 JZ9 用兩個棧實現隊列一個棧in用作進元素,一個棧out用于出元素。當棧out沒有元素時,從in棧獲取數據,根據棧的特性,棧out的top元素一定是先進入的元素,因此當棧out使用pop操作時,一定時滿足隊…

GoView 低代碼數據可視化

純前端 分支: master 👻 攜帶 后端 請求分支: master-fetch 📚 GoView 文檔 地址:https://www.mtruning.club/ 項目純前端-Demo 地址:https://vue.mtruning.club/ 項目帶后端-Demo 地址:https://demo.mtrun…

Spring Boot返回前端Long型丟失精度 后兩位 變成00

文章目錄一、前言二、問題描述2.1、問題背景2.2、問題示例三、解決方法3.1、將ID轉換為字符串3.2、使用JsonSerialize注解3.3、使用JsonFormat注解一、前言 在后端開發中,我們經常會遇到需要將ID作為標識符傳遞給前端的情況。當ID為long類型時,如果該ID…

計算機網絡實驗——無線局域網安全實驗

實驗1. WEP和WPA2-PSK實驗一、實驗目的驗證AP和終端與實現WEP安全機制相關的參數的配置過程。驗證AP和終端與實現WPA2-PSK安全機制相關的參數的配置過程。驗證終端與AP之間建立關聯的過程。驗證關閉端口的重新開啟過程。驗證屬于不同BSS的終端之間的數據傳輸過程。二、實驗任務…

【從零開始學Dify】大模型應用開發平臺Dify本地化部署

目錄Dify一、本地化部署1、安裝docker2、安裝Dify(1)拉取代碼到本地(2)docker部署(3)查看服務狀態(4)web端部署(5)登錄二、可能會出現的問題(1&am…