Vue3.js“非原始值”響應式實現基本原理筆記(一)

如果您覺得這篇文章有幫助的話!給個點贊和評論支持下吧,感謝~

作者:前端小王hs

阿里云社區博客專家/清華大學出版社簽約作者/csdn百萬訪問前端博主/B站千粉前端up主

此篇文章是博主于2022年學習《Vue.js設計與實現》時的筆記整理而來

書籍:《Vue.js設計與實現》 作者:霍春陽

本篇博文將在書第5.1節5.4節的基礎上進一步總結所提到的基礎概念,附加了測試的代碼運行示例,方便正在學習Vue3想分析Vue3源碼的朋友快速閱讀

如有幫助,不勝榮幸

5.1 Proxy和Reflect

代理與被代理

5.1節開篇給到了一個信息:Proxy 只能代理對象,無法代理非對象值,例如字符串、布爾值等(原文)

關于什么是代理,可以舉個簡單的例子,有ab兩個對象,如果我們想通過b去訪問a里的屬性,那么這個b就是代理

可以理解這個b為中介,而這個b,就是new Proxyproxy對象,如下代碼所示:

const b = new Proxy(a, {
})

對象a就是被代理對象ab代理了),位于new Proxy第一個參數,而(new Proxy,下同)第二個參數是一個對象,里面包含了如get()set()之類的攔截方法,關于這一點,在之前的筆記中深入理解Vue3.js響應式系統基礎邏輯也提到了

代理的作用

代理的作用在于可以攔截一些基本操作,如讀取修改對象等

邏輯也非常簡單,原來通過a.foo可以訪問到a對象里的foo屬性,現在代理了就變成通過b.foo去訪問了,當訪問時就會觸發第二個參數里設置的如get()set()之類的攔截方法,那么經過這些方法的攔截,就可以進行一些額外的操作,例如前文筆記里提到的響應式

Proxy攔截函數

函數也是對象,那么同理可以把一個函數fn當作a變為被代理對象,那么同理,當調用fn時會觸發第二個參數內的攔截方法

apply與call

書中舉例了一個使用代理對象去調用fn的例子,代碼如下:

function fn(name) {return '我是:' + name;
}// 使用 Proxy 攔截對 fn 的調用  
const p = new Proxy(fn, {apply(target, thisArg, argArray) {return target.call(thisArg, ...argArray);}
})p('123') // 我是123

這里的applyproxy支持的13個攔截方法之一,在阮一峰大佬的ES6中對apply也有詳細的介紹:

apply(target, object, args) :攔截 Proxy 實例作為函數調用的操作,比如proxy(...args)proxy.call(object, ...args)proxy.apply(...)

這里的三個參數分別是:

  1. target:目標對象
  2. object:目標對象的上下文對象(this)
  3. args:目標對象的參數數組

回看上面的例子,apply接收的三個形參的內容分別是:fnthis(undefined)、包含123的參數數組

接著返回了target.call(thisArg, ...argArray);,也就是fn.call(undefined,'123'),或者說fn('123')

這里的一個問題是,我們知道此時this指向的是調用者(使用了call),也就是fn,那第一個參數thisArg其實也就沒有發揮作用,或者說一直都是undefined

這里其實有個潛在條件就是,使用proxy.apply的基本場景就是去攔截函數

整個流程其實就是:

  1. p代理了fn
  2. 傳入123,被apply攔截
  3. 在攔截的邏輯里執行fn('123')

Reflect的作用

Proxy的方法,在Reflect都能找到,也就是說ProxygetReflect里也有

Reflect.get(target, name, receiver)Reflect.set(target, name, value, receiver)的作用和Proxy內的getset相同

書中提到Reflect原因是,使用target即原始對象去完成對屬性的讀取,無法完成與副作用函數的綁定

我們來分析一下書中的例子,下面是代碼:

const obj = {foo: 1,get bar() {return this.foo;}
};  const p = new Proxy(obj, {get(target, key) {track(target, key);return target[key];},set(target, key, newVal) {  target[key] = newVal;trigger(target, key);}  
});  effect(() => {console.log(p.bar);
});  p.foo++;

這段代碼的問題是,執行p.foo++,不會觸發副作用函數,這是為什么?

直接看當前的執行邏輯是怎么樣的:

  1. 執行effect,那么會輸出p.bar,那么會觸發get攔截
  2. track中,targetobjkey字符串bar,也就是objbar會和當前effect建立聯系(這一步不重要)
  3. 返回target[key],那么觸發getter,此時這里的this是指obj,也就是最終返回的是obj.foo副作用函數
effect(()=>{ obj.foo })

也就是說,匿名函數輸出p.bar,返回的是obj.foo,那就很好理解了,obj不是代理對象,在副作用函數里輸出obj.foo不會觸發Proxy.get攔截,自然就不會與副作用函數進行聯系了

解決的辦法就是使用Reflect.get(target, key, receiver)代替target[key]

Reflect.get(target, key, receiver)返回也是obj.foo,但它的第三個參數receiver可以指出是誰在調用

那么代碼就更新如下:

const p = new Proxy(obj, {get(target, key,receiver) {track(target, key);return Reflect.get(target, key, receiver);},// ...
}); 

那么現在,就可以把obj.foo變為p.foo

5.2 JavaScript 對象及 Proxy 的工作原理

對象分為兩種,常規對象異質對象

區分常規對象異質對象的區別在于其內部方法是使用ECMA的哪一種規范決定的,這里不去詳細贅述。需要明白的是Proxy是一個異質對象

如何區分普通對象函數對象呢?文中提到:對象的實際語義是由對象的內部方法(internal method)指定的(原文)

最簡單的一個區分方法是,函數對象call()方法

內部方法具有多態性

在書中提到了代理透明性質,也就是如果定義了一個代理對象p,但是內部沒有指定get(),那么通過p去訪問被代理對象的某個屬性,會調用原始對象的內部方法[[Get]]。這一點在阮一峰ES6關于proxy.get一節也有記載

Proxy對象部署的所有內部方法

內部方法處理器函數使用場景
[[GetPrototypeOf]]getPrototypeOf獲取對象原型
[[SetPrototypeOf]]setPrototypeOf設置對象原型
[[IsExtensible]]isExtensible判斷對象是否可以新增屬性
[[PreventExtensions]]preventExtensions阻止對象新增屬性
[[GetOwnProperty]]getOwnProperty獲取對象自有屬性的屬性描述符
[[DefineOwnProperty]]defineProperty定義對象新屬性或修改現有屬性,返回鍍錫
[[HasProperty]]has判斷對象是否有指定的屬性
[[Get]]get獲取對象的屬性值
[[Set]]set設置對象的屬性值
[[Delete]]deleteProperty刪除對象的屬性
[[OwnPropertyKeys]]ownKeys獲取對象所有自有屬性的鍵
[[Call]]apply調用函數
[[OwnPropertyKeys]]Construct創建一個新的實例

書上的表格無使用場景,這里加上便于理解

在書上的例子是舉例了deleteProperty,代碼如下:

const obj = { foo: 1 }
const p = new Proxy(obj, {deleteProperty(target, key) {return Reflect.deleteProperty(target, key)}
})console.log(p.foo) // 1
delete p.foo
console.log(p.foo) // undefined

那么需要注意的是deletePropertyProxy對象即p的內部方法,只有刪除p的屬性時才會被調用,其實就和p讀取obj屬性時才會調用get一個意思。在上述代碼中,上下文環境要刪除的是obj.foo,所以調用了Reflect.deleteProperty,回想一下,Proxy的方法和Reflect里的方法是一樣的名字

問題總結

  1. JS中的代理是什么
  2. 結合Vue3響應式理解apply和call
  3. 了解ES6的Reflect在攔截函數中的作用
  4. 什么是常規對象和異質對象?
  5. 如何區分普通對象和函數對象
  6. Proxy對象的內部方法及其使用場景

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

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

相關文章

Sentinel限流算法總結

文章目錄 一、線程隔離二、滑動窗口算法三、令牌桶算法四、漏桶算法 一、線程隔離 線程隔離有兩種方式實現: 線程池隔離:給每個服務調用業務分配一個線程池,利用線程池本身實現隔離效果信號量隔離:不創建線程池,而是…

Xilinx FPGA:vivado關于同步fifo的兩個小實驗

一、實驗一:在同步fifo里寫一個讀一個(寫入是8個位寬,讀出是16個位寬) 程序: timescale 1ns / 1ps //要求寫一個讀一個 //讀寫時鐘一致,寫是8個位寬,讀是16個位寬 module sync_fifo_test(inpu…

QQ音樂Android一面涼經

最近面試了不少公司, 近期告一段落, 整理一下各家的面試問題, 打算陸續發布出來, 供有緣人參考。今天給大家帶來的是QQ音樂Android一面涼經。 面試崗位: QQ音樂Android開發工程師面試時長: 50min(提問40min 反問10min)代碼考核: 無 面試問題(40min) 自我介紹 工作經歷, 重點…

銀行信用卡風險大數據分析與挖掘2024

銀行信用卡風險大數據分析與挖掘 使用excel數據挖掘功能完成 一、信用卡客戶信用等級影響因素分析與挖掘 基于客戶信用記錄表 1. 數據預處理 瀏覽數據 客戶等級占比,其中優質客戶占比較少,風險客戶很多,分析影響客戶信用等級的原因 年…

vue3+ts項目中.env配置環境變量與情景配置

一、環境變量配置 官網https://cn.vitejs.dev/guide/env-and-mode.html#intellisense 1. 新建.env開頭的文件在根目錄 為了防止意外地將一些環境變量泄漏到客戶端,只有以 VITE_ 為前綴的變量才會暴露給經過 vite 處理的代碼 .env 所有環境默認加載 .env.developm…

數字化精益生產系統--MRP 需求管理系統

MRP(Material Requirements Planning,物料需求計劃)需求管理系統是一種在制造業中廣泛應用的計劃工具,旨在通過分析和計劃企業生產和庫存需求,優化資源利用,提高生產效率。以下是對MRP需求管理系統的功能設…

Raylib 坐標系

draftx 符號調整為正數 發現采樣坐標系原點0&#xff0c;0 在左上角&#xff0c;正方向 右&#xff0c;下 繪制坐標系 原點0&#xff0c;0 在左下角&#xff0c;正方向 右&#xff0c;上 拖拽可得 #include <raylib.h> // 重整原因&#xff1a;解決新函數放大縮小之下…

當需要對多個表進行聯合更新操作時,怎樣確保數據的一致性?

文章目錄 一、問題分析二、解決方案三、示例代碼&#xff08;以 MySQL 為例&#xff09;四、加鎖機制示例五、測試和驗證六、總結 在數據庫管理中&#xff0c;經常會遇到需要對多個表進行聯合更新的情況。這種操作帶來了一定的復雜性&#xff0c;因為要確保在整個更新過程中數據…

為什么需要服務器?服務器可以做些什么

目錄 一、服務器和電腦的區別二、什么是SSH三、什么是免密碼登錄四、服務器如何實現SSH免密碼登錄 一、服務器和電腦的區別 服務器和電腦是兩種不同類型的計算機系統&#xff0c;它們在設計、功能和用途上存在明顯的區別。首先&#xff0c;從硬件配置上看&#xff0c;服務器通…

vb.netcad二開自學筆記3:啟動與銷毀

Imports Autodesk.AutoCAD.ApplicationServicesImports Autodesk.AutoCAD.EditorInputImports Autodesk.AutoCAD.RuntimePublic Class WellcomCADImplements IExtensionApplicationPublic Sub Initialize() Implements IExtensionApplication.InitializeMsgBox("net程序已…

JDK都出到20多了,你還不會使用JDK8的Stream流寫代碼嗎?

目錄 前言 Stream流 是什么&#xff1f; 為什么要用Steam流 常見stream流使用案例 映射 map() & 集合 collect() 單字段映射 多字段映射 映射為其他的對象 映射為 Map 去重 distinct() 過濾 filter() Stream流的其他方法 使用Stream流的弊端 前言 當你某天看…

基于深度學習LightWeight的人體姿態檢測跌倒系統源碼

一. LightWeight概述 light weight openpose是openpose的簡化版本&#xff0c;使用了openpose的大體流程。 Light weight openpose和openpose的區別是&#xff1a; a 前者使用的是Mobilenet V1&#xff08;到conv5_5&#xff09;&#xff0c;后者使用的是Vgg19&#xff08;前10…

公務員考試、事業編考試、教師資格證、面試、K12資料、電子書

點擊上方△騰陽 關注 作者 l 騰陽 轉載請聯系授權 你好&#xff0c;我是騰陽。 在這個自媒體的海洋里&#xff0c;我曾是一只迷失方向的小鳥&#xff0c;多次嘗試飛翔卻總是跌跌撞撞。 但每一次跌倒&#xff0c;都讓我更堅定地相信&#xff0c;只要不放棄&#xff0c;總…

【Unity2D 2022:Particle System】添加命中粒子特效

一、創建粒子特效游戲物體 二、修改粒子系統屬性 1. 基礎屬性 &#xff08;1&#xff09;修改發射粒子持續時間&#xff08;Duration&#xff09;為1s &#xff08;2&#xff09;取消勾選循環&#xff08;Looping&#xff09; &#xff08;2&#xff09;修改粒子存在時間&…

2024全網最全面及最新且最為詳細的網絡安全技巧五 之 SSRF 漏洞EXP技巧,典例分析以及 如何修復 (上冊)———— 作者:LJS

五——SSRF漏洞 EXP技巧&#xff0c;典例分析以及 如何修復 目錄 五——SSRF EXP技巧&#xff0c;典例分析以及 如何修復 5.1Apache mod_proxy SSRF&#xff08;CVE-2021-40438&#xff09;的一點分析和延伸 0x01 Apache Module綜述 0x02 漏洞原理分析 Apache在配置反代的后端…

Vue的學習之生命周期

一、生命周期 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>Vue的學習</title><script src"vue.js" type"text/javascript" charset"utf-8"></script></head>&l…

C#如何從中級進階到高級開發

從中級C#開發進階到高級開發&#xff0c;需要深入理解和掌握更復雜的技術和架構&#xff0c;同時培養解決問題的能力和創新思維。以下是一些關鍵的技能和步驟&#xff0c;可以幫助你從中級向高級開發邁進&#xff1a; 1. 深入理解C#語言特性 泛型&#xff1a;熟練使用泛型提高…

Java實現登錄驗證 -- JWT令牌實現

目錄 1.實現登錄驗證的引出原因 2.JWT令牌2.1 使用JWT令牌時2.2 令牌的組成 3. JWT令牌&#xff08;token&#xff09;生成和校驗3.1 引入JWT令牌的依賴3.2 使用Jar包中提供的API來實現JWT令牌的生成和校驗3.3 使用JWT令牌驗證登錄3.4 令牌的優缺點 1.實現登錄驗證的引出 傳統…

強化Linux系統安全性:從基礎命令到高級管理

強化Linux系統安全性&#xff1a;從基礎命令到高級管理 引言 在網絡安全領域&#xff0c;Linux系統因其穩定性和安全性而廣受歡迎。作為一名網絡安全專家&#xff0c;我將分享如何通過Linux基礎命令和高級管理技巧來加強系統的安全性。本文將基于《學神 IT 教育》提供的Linux…

Debezium報錯處理系列之第110篇: ERROR Error during binlog processing.Access denied

Debezium報錯處理系列之第110篇:ERROR Error during binlog processing. Last offset stored = null, binlog reader near position = /4 Access denied; you need at least one of the REPLICATION SLAVE privilege for this operation 一、完整報錯二、錯誤原因三、解決方法…