版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第js中為什么Proxy一定要配合Reflect使用目錄引言前置知識單獨(dú)使用ProxyProxy中的receiverReflect中的receiver總結(jié)結(jié)尾
引言
EcmaScript2015中引入了Proxy代理與Reflect反射兩個(gè)新的內(nèi)置模塊。
我們可以利用Proxy和Reflect來實(shí)現(xiàn)對于對象的代理劫持操作,類似于Es5中Object.defineProperty()的效果,不過ReflectProxy遠(yuǎn)遠(yuǎn)比它強(qiáng)大。
大多數(shù)開發(fā)者都了解這兩個(gè)Es6中的新增內(nèi)置模塊,可是你也許并不清楚為什么Proxy一定要配合Reflect使用。
這里,文章通過幾個(gè)通俗易懂的例子來講述它們之間相輔相成的關(guān)系。
前置知識
Proxy代理,它內(nèi)置了一系列陷阱用于創(chuàng)建一個(gè)對象的代理,從而實(shí)現(xiàn)基本操作的攔截和自定義(如屬性查找、賦值、枚舉、函數(shù)調(diào)用等)。
Reflect反射,它提供攔截JavaScript操作的方法。這些方法與Proxy的方法相同。
簡單來說,我們可以通過Proxy創(chuàng)建對于原始對象的代理對象,從而在代理對象中使用Reflect達(dá)到對于JavaScript原始操作的攔截。
如果你還不了解,那么趕快去MDN上去補(bǔ)習(xí)他們的知識吧。
畢竟大名鼎鼎的VueJs/Core中核心的響應(yīng)式模塊就是基于這兩個(gè)Api來實(shí)現(xiàn)的。
單獨(dú)使用Proxy
開始的第一個(gè)例子,我們先單獨(dú)使用Proxy來烹飪一道簡單的開胃小菜:
constobj={
name:'wang.haoyu',
constproxy=newProxy(obj,{
//get陷阱中target表示原對象key表示訪問的屬性名
get(target,key){
console.log('劫持你的數(shù)據(jù)訪問'+key);
returntarget[key]
//劫持你的數(shù)據(jù)訪問name-wang.haoyu
看起來很簡單對吧,我們通過Proxy創(chuàng)建了一個(gè)基于obj對象的代理,同時(shí)在Proxy中聲明了一個(gè)get陷阱。
當(dāng)訪問我們訪問時(shí)實(shí)際觸發(fā)了對應(yīng)的get陷阱,它會執(zhí)行g(shù)et陷阱中的邏輯,同時(shí)會執(zhí)行對應(yīng)陷阱中的邏輯,最終返回對應(yīng)的target[key]也就是所謂的wang.haoyu.
Proxy中的receiver
上邊的Demo中一切都看起來順風(fēng)順?biāo)疀]錯吧,細(xì)心的同學(xué)在閱讀Proxy的MDN文檔上可能會發(fā)現(xiàn)其實(shí)Proxy中g(shù)et陷阱中還會存在一個(gè)額外的參數(shù)receiver。
那么這里的receiver究竟表示什么意思呢?大多數(shù)同學(xué)會將它理解成為代理對象,但這是不全面的。
接下來同樣讓我們以一個(gè)簡單的例子來作為切入點(diǎn):
constobj={
name:'wang.haoyu',
constproxy=newProxy(obj,{
//get陷阱中target表示原對象key表示訪問的屬性名
get(target,key,receiver){
console.log(receiver===proxy);
returntarget[key];
//log:true
;
上述的例子中,我們在Proxy實(shí)例對象的get陷阱上接收了receiver這個(gè)參數(shù)。
同時(shí),我們在陷阱內(nèi)部打印console.log(receiver===proxy);它會打印出true,表示這里receiver的確是和代理對象相等的。
所以receiver的確是可以表示代理對象,但是這僅僅是receiver代表的一種情況而已。
接下來我們來看另外一個(gè)例子:
constparent={
getvalue(){
return'19Qingfeng';
constproxy=newProxy(parent,{
//get陷阱中target表示原對象key表示訪問的屬性名
get(target,key,receiver){
console.log(receiver===proxy);
returntarget[key];
constobj={
name:'wang.haoyu',
//設(shè)置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj,proxy);
//log:false
obj.value
關(guān)于原型上出現(xiàn)的get/set屬性訪問器的屏蔽效果,我在這篇文章中進(jìn)行了詳細(xì)闡述。這里我就不展開講解了。
我們可以看到,上述的代碼同樣我在proxy對象的get陷阱上打印了console.log(receiver===proxy);結(jié)果卻是false。
那么你可以稍微思考下這里的receiver究竟是什么呢?其實(shí)這也是proxy中g(shù)et陷阱第三個(gè)receiver存在的意義。
它是為了傳遞正確的調(diào)用者指向,你可以看看下方的代碼:
...
constproxy=newProxy(parent,{
//get陷阱中target表示原對象key表示訪問的屬性名
get(target,key,receiver){
-console.log(receiver===proxy)//log:false
+console.log(receiver===obj)//log:true
returntarget[key];
...
其實(shí)簡單來說,get陷阱中的receiver存在的意義就是為了正確的在陷阱中傳遞上下文。
涉及到屬性訪問時(shí),不要忘記get陷阱還會觸發(fā)對應(yīng)的屬性訪問器,也就是所謂的get訪問器方法。
我們可以清楚的看到上述的receiver代表的是繼承與Proxy的對象,也就是obj。
看到這里,我們明白了Proxy中g(shù)et陷阱的receiver不僅僅代表的是Proxy代理對象本身,同時(shí)也許他會代表繼承Proxy的那個(gè)對象。
其實(shí)本質(zhì)上來說它還是為了確保陷阱函數(shù)中調(diào)用者的正確的上下文訪問,比如這里的receiver指向的是obj。
當(dāng)然,你不要將revceiver和get陷阱中的this弄混了,陷阱中的this關(guān)鍵字表示的是代理的handler對象。
比如:
constparent={
getvalue(){
return'19Qingfeng';
consthandler={
get(target,key,receiver){
console.log(this===handler);//log:true
console.log(receiver===obj);//log:true
returntarget[key];
constproxy=newProxy(parent,handler);
constobj={
name:'wang.haoyu',
//設(shè)置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj,proxy);
//log:false
obj.value
Reflect中的receiver
在清楚了Proxy中g(shù)et陷阱的receiver后,趁熱打鐵我們來聊聊Reflect反射API中g(shù)et陷阱的receiver。
我們知道在Proxy中(以下我們都以get陷阱為例)第三個(gè)參數(shù)receiver代表的是代理對象本身或者繼承與代理對象的對象,它表示觸發(fā)陷阱時(shí)正確的上下文。
constparent={
name:'19Qingfeng',
getvalue(){
return;
consthandler={
get(target,key,receiver){
returnReflect.get(target,key);
//這里相當(dāng)于returntarget[key]
constproxy=newProxy(parent,handler);
constobj={
name:'wang.haoyu',
//設(shè)置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj,proxy);
//log:false
console.log(obj.value);
我們稍微分析下上邊的代碼:
當(dāng)我們調(diào)用obj.value時(shí),由于obj本身不存在value屬性。
它繼承的proxy對象中存在value的屬性訪問操作符,所以會發(fā)生屏蔽效果。
此時(shí)會觸發(fā)proxy上的getvalue()屬性訪問操作。
同時(shí)由于訪問了proxy上的value屬性訪問器,所以此時(shí)會觸發(fā)get陷阱。
進(jìn)入陷阱時(shí),target為源對象也就是parent,key為value。
陷阱中返回Reflect.get(target,key)相當(dāng)于target[key]。
此時(shí),不知不覺中this指向在get陷阱中被偷偷修改掉了??!
原本調(diào)用方的obj在陷阱中被修改成為了對應(yīng)的target也就是parent。
自然而然打印出了對應(yīng)的parent[value]也就是19Qingfeng。
這顯然不是我們期望的結(jié)果,當(dāng)我訪問obj.value時(shí),我希望應(yīng)該正確輸出對應(yīng)的自身上的name屬性也就是所謂的obj.value=wang.haoyu。
那么,Relfect中g(shù)et陷阱的receiver就大顯神通了。
constparent={
name:'19Qingfeng',
getvalue(){
return;
consthandler={
get(target,key,receiver){
-returnReflect.get(target,key);
+returnReflect.get(target,key,receiver);
constproxy=newProxy(parent,handler);
constobj={
name:'wang.haoyu',
//設(shè)置obj繼承與parent的代理對象proxy
Object.setPrototypeOf(obj,proxy);
//log:wang.haoyu
console.log(obj.value);
上述代碼原理其實(shí)非常簡單:
首先,之前我們提到過在Proxy中g(shù)et陷阱的receiver不僅僅會表示代理對象本身同時(shí)也還有可能表示繼承于代理對象的對象,具體需要區(qū)別與調(diào)用方。這里顯然它是指向繼承與代理對象的obj。
其次,我們在Reflect中g(shù)et陷阱中第三個(gè)參數(shù)傳遞了Proxy中的receiver也就是obj作為形參,它會修改調(diào)用時(shí)的this指向。
你可以簡單的將Reflect.get(target,key,receiver)理解成為target[key].call(receiver),不過這是一段偽代碼,但是這樣你可能更好理解。
相信看到這里你已經(jīng)明白Relfect中的receiver代表的含義是什么了,沒錯它正是可以修改屬性訪問中的this指向?yàn)閭魅氲膔eceiver對象。
總結(jié)
相信看到這里大家都已經(jīng)明白了,為什么Proxy一定要配合Reflect使用。恰恰是為什么觸發(fā)代理對象的劫持時(shí)保證正確的this上下文指向。
我們再來稍稍回憶一下,針對于get陷阱(當(dāng)然set其他之類涉及到receiver的陷阱同理):
Proxy中接受的Receiver形參表示代理對象本身或者繼承與代理對象的對象。
Reflect中傳遞的Receiver實(shí)參表示修改執(zhí)行原始操作時(shí)的this指向。
結(jié)尾
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 深度解析(2026)《WBT 1070-2018汽車物流統(tǒng)計(jì)指標(biāo)體系》
- 深度解析(2026)《TBT 3439-2016列控中心技術(shù)條件》
- 深度解析(2026)《TBT 3148-2017軌道檢測 測量儀器 支距尺》
- 深度解析(2026)《SYT 7794-2024 海上時(shí)移地震技術(shù)規(guī)程》
- 北交所新股交易制度
- 小學(xué)教師交流合作方案
- 2025-2026冀教版初中二年級數(shù)學(xué)上學(xué)期期末測試卷
- 倉庫防盜監(jiān)控系統(tǒng)方案
- 2025-2026冀教版初中八年級美術(shù)期末測試卷
- 2025至2030中國工業(yè)廢水零排放技術(shù)路線比較及成本效益評估分析報(bào)告
- 2025年農(nóng)村人居環(huán)境五年評估報(bào)告
- 浙江省杭州市拱墅區(qū)2024-2025學(xué)年四年級上冊期末考試數(shù)學(xué)試卷(含答案)
- 房屋過戶給子女的協(xié)議書的范文
- 超聲振動珩磨裝置的總體設(shè)計(jì)
- 新媒體藝術(shù)的發(fā)展歷程及藝術(shù)特征
- 醫(yī)保違規(guī)行為分類培訓(xùn)課件
- 講課學(xué)生數(shù)學(xué)學(xué)習(xí)成就
- 醫(yī)療器械法規(guī)對互聯(lián)網(wǎng)銷售的限制
- 西葫蘆栽培技術(shù)要點(diǎn)
- 系桿拱橋系桿預(yù)應(yīng)力施工控制要點(diǎn)
- 三亞市海棠灣椰子洲島土地價(jià)格咨詢報(bào)告樣本及三洲工程造價(jià)咨詢有限公司管理制度
評論
0/150
提交評論