JavaScript?對(duì)象管家?Proxy
正文
JavaScript 在 ES6 中,引入了一個(gè)新的對(duì)象類型 Proxy
,它可以用來(lái)代理另一個(gè)對(duì)象,并可以在代理過(guò)程中攔截、覆蓋和定制對(duì)象的操作。Proxy
對(duì)象封裝另一個(gè)對(duì)象并充當(dāng)中間人,其提供了一個(gè)捕捉器函數(shù),可以在代理對(duì)象上攔截所有的操作,包括訪問(wèn)屬性、賦值屬性、函數(shù)調(diào)用等等。通過(guò)攔截這些操作,可以對(duì)代理對(duì)象進(jìn)行定制和控制。
在開始介紹 Proxy
對(duì)象前先了解 3 個(gè)術(shù)語(yǔ):
target 目標(biāo)對(duì)象
:要代理的對(duì)象或函數(shù)。handler 處理程序
:對(duì)代理的對(duì)象或函數(shù)執(zhí)行某些操作的函數(shù)。traps 捕捉器
:這些是一些用于處理目標(biāo)的函數(shù)。單擊此處閱讀有關(guān)陷阱的更多信息。
語(yǔ)法
Proxy
對(duì)象的基本語(yǔ)法如下:
new Proxy(target, handler);
其中,target
是被代理的目標(biāo)對(duì)象,handler
是一個(gè)對(duì)象,它包含了一些捕捉器函數(shù),用來(lái)攔截代理對(duì)象的操作。
下面是一些常見的攔截操作和對(duì)應(yīng)的捕捉器函數(shù):
對(duì)象方法
getPrototypeOf()
:Object.getPrototypeOf
方法的捕捉器。setPrototypeOf()
:Object.setPrototypeOf
方法的捕捉器。isExtensible()
:Object.isExtensible
方法的捕捉器。preventExtensions()
:Object.preventExtensions
方法的捕捉器。getOwnPropertyDescriptor()
:Object.getOwnPropertyDescriptor
方法的捕捉器。handler.defineProperty()
:Object.defineProperty
方法的捕捉器。
屬性獲取器/設(shè)置器
get(target, propKey, receiver)
:攔截對(duì)象的讀取屬性操作,返回屬性值。set(target, propKey, value, receiver)
:攔截對(duì)象的設(shè)置屬性操作,返回一個(gè)布爾值表示是否設(shè)置成功。has(target, propKey)
:攔截對(duì)象的in
操作符,返回一個(gè)布爾值表示對(duì)象是否包含該屬性。deleteProperty(target, propKey)
:攔截對(duì)象的delete
操作符,返回一個(gè)布爾值表示是否刪除成功。ownKeys()
:Object.getOwnPropertyNames
方法和Object.getOwnPropertySymbols
方法的捕捉器
函數(shù)方法
如果目標(biāo)對(duì)象是一個(gè)函數(shù),可以使用下面 2 個(gè)捕捉器。
apply(target, thisArg, args)
:攔截函數(shù)的調(diào)用操作,返回調(diào)用結(jié)果。construct(target, args, newTarget)
:攔截new
操作符,返回一個(gè)對(duì)象。
Proxy
在目標(biāo)對(duì)象周圍創(chuàng)建一個(gè)不可檢測(cè)的屏障,將所有操作重定向到處理程序?qū)ο蟆H绻l(fā)送一個(gè)空的 handler
,代理只是原始對(duì)象的一個(gè)空包裝器。
const author = { name: "Quintion", age: 36, }; const proxyAuthor = new Proxy(author, {}); console.log(author.name); // Quintion console.log(proxyAuthor.name); // Quintion
為了賦予代理意義,需要向處理程序添加一些操作方法。
捕捉器
每當(dāng)與一個(gè)對(duì)象交互時(shí),都在調(diào)用一個(gè)內(nèi)部方法。代理允許使用捕捉器攔截給定內(nèi)部方法的執(zhí)行。
因此,當(dāng)運(yùn)行 author.name
時(shí),告訴 JavaScript 引擎調(diào)用內(nèi)部 [[GET]]
方法來(lái)檢索 name
屬性。當(dāng)運(yùn)行 proxyAuthor.name
時(shí),get
捕捉器會(huì)調(diào)用處理程序中定義的 get()
函數(shù)來(lái)執(zhí)行,然后再將調(diào)用發(fā)送到原始對(duì)象。
get
get()
方法有兩個(gè)必需的參數(shù):
target
— 傳遞給代理的對(duì)象。property
— 訪問(wèn)的屬性的名稱。
要自定義代理,在處理程序?qū)ο笊隙x函數(shù)。下面定義了 get
方法來(lái)記錄訪問(wèn):
const handler = { get(target, property) { console.log(`捕捉器 GET:${property}`); return target[property]; }, };
為了讓調(diào)用通過(guò),捕捉器 get
返回 target[property]
。使用方式如下:
const author = { name: "Quintion", age: 36, }; const handler = { get(target, property) { console.log(`捕捉器 GET[${property}]`); return target[property]; }, }; const proxyAuthor = new Proxy(author, handler); console.log(proxyAuthor.name);
執(zhí)行后,將打印以下內(nèi)容:
捕捉器 GET[name]
Quintion
set
set
捕捉器用于給目標(biāo)對(duì)象進(jìn)行賦值操作,返回值是一個(gè)布爾值。set
捕捉器需要的參數(shù)如下:
target
— 傳遞給代理的對(duì)象。property
— 將被設(shè)置的屬性名或 Symbol。value
— 新的屬性值receiver
— 最初被調(diào)用的對(duì)象。
下面通過(guò) set
捕捉器驗(yàn)證年齡值的輸入:
const handler = { set(target, property, value) { if (property === "age" && typeof value !== "number") { throw new TypeError("年齡必須是一個(gè)數(shù)字"); } target[property] = value; return true; }, };
下面嘗試將錯(cuò)誤的類型值賦值給 age
,則會(huì)拋出錯(cuò)誤:
const proxyAuthor = new Proxy(author, handler); proxyAuthor.age = "young"; // 執(zhí)行后拋出異常:throw new TypeError("年齡必須是一個(gè)數(shù)字");
set()
方法應(yīng)該返回一個(gè)布爾值 true
用來(lái)表示賦值成功。 在嚴(yán)格模式下運(yùn)行,并且返回一個(gè)假值或什么都不返回,則會(huì)拋出錯(cuò)誤。
除了攔截對(duì)屬性的讀取和修改,Proxy
總共可以攔截 13 種操作。
應(yīng)用場(chǎng)景
通過(guò) Proxy
對(duì)象的特征,可以將其使用在下面這些場(chǎng)合:
驗(yàn)證和過(guò)濾
代理Proxy
用于攔截和驗(yàn)證對(duì)對(duì)象屬性的訪問(wèn)。如,可以創(chuàng)建一個(gè)代理來(lái)檢查用戶輸入的數(shù)據(jù)是否符合預(yù)期的格式,并拒絕不正確的數(shù)據(jù)。就如下面 age
屬性賦值判斷
緩存
代理Proxy
用于緩存對(duì)象的操作結(jié)果,以避免重復(fù)計(jì)算。如,可以創(chuàng)建一個(gè)代理來(lái)攔截對(duì)象的某些方法,并將結(jié)果存儲(chǔ)在緩存中,以便將來(lái)使用。
下面是一個(gè)基于 Proxy 的緩存庫(kù)的示例:
class Cache { constructor() { this.cache = new Map(); this.proxy = new Proxy(this, { get(target, property) { if (property === "get") { return (key) => { return target.cache.get(key); }; } if (property === "set") { return (key, value) => { target.cache.set(key, value); }; } if (property === "has") { return (key) => { return target.cache.has(key); }; } if (property === "delete") { return (key) => { return target.cache.delete(key); }; } }, }); } }
在上面的代碼中,定義了一個(gè) Cache
類,該類中包含一個(gè)內(nèi)部的 Map
對(duì)象用于存儲(chǔ)緩存數(shù)據(jù),并且定義了一個(gè) proxy
對(duì)象作為該類的代理。
在 proxy
對(duì)象的 get
方法中,根據(jù)傳入的屬性名返回相應(yīng)的方法。如果屬性名為 get
,則返回一個(gè)可以獲取緩存值的方法;如果屬性名為 set
,則返回一個(gè)可以設(shè)置緩存值的方法;如果屬性名為 has
,則返回一個(gè)可以判斷是否存在緩存值的方法;如果屬性名為 delete
,則返回一個(gè)可以刪除緩存值的方法。
下面是一個(gè)使用該緩存庫(kù)的示例:
const cacheHelper = new Cache(); cacheHelper.set("foo", "bar"); console.log(cacheHelper.get("foo")); // "bar" console.log(cacheHelper.has("foo")); // true cacheHelper.delete("foo"); console.log(cacheHelper.get("foo")); // undefined console.log(cacheHelper.has("foo")); // false
在上面的代碼中,創(chuàng)建了一個(gè) Cache
對(duì)象,并調(diào)用其 set
方法設(shè)置緩存值,然后調(diào)用其 get
方法獲取緩存值,并調(diào)用其 has 方法判斷緩存值是否存在,最后調(diào)用其 delete
方法刪除緩存值。
監(jiān)聽屬性變化
代理Proxy
用于監(jiān)視對(duì)象屬性的變化,并在屬性發(fā)生變化時(shí)觸發(fā)其他操作。如,創(chuàng)建一個(gè)代理來(lái)監(jiān)視對(duì)象屬性的變化,并在屬性發(fā)生變化時(shí)更新頁(yè)面上的元素。
防止誤操作
代理Proxy
用于防止誤操作,如,創(chuàng)建一個(gè)代理來(lái)攔截對(duì)象的某些方法,并在方法調(diào)用時(shí)檢查一些條件,以確保方法只在正確的上下文中調(diào)用。
虛擬化
代理Proxy
可以用于創(chuàng)建虛擬化對(duì)象。如,創(chuàng)建一個(gè)代理對(duì)象,用于代替某個(gè)對(duì)象的真實(shí)實(shí)現(xiàn),并且在實(shí)際對(duì)象執(zhí)行之前,對(duì)其進(jìn)行修改或攔截。
總結(jié)
上面介紹了如何使用代理Proxy
對(duì)象來(lái)監(jiān)視對(duì)象,通過(guò)使用處理程序?qū)ο笾械牟蹲狡鞣椒ㄏ蛩鼈兲砑幼远x行為,提供更高級(jí)的對(duì)象操作和控制功能,從而增強(qiáng)代碼的可讀性和可維護(hù)性。
以上就是JavaScript 對(duì)象管家 Proxy的詳細(xì)內(nèi)容,更多關(guān)于JavaScript對(duì)象Proxy的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
徒手實(shí)現(xiàn)關(guān)于JavaScript的24+數(shù)組方法
數(shù)組是我們?nèi)粘9ぷ髦杏玫淖铑l繁的一類數(shù)據(jù)結(jié)構(gòu),能幫助我們解決許多問(wèn)題,而其本身也包含接近33個(gè)之多的方法,做了一個(gè)腦圖分類如下,熟練使用數(shù)組的你,是否想知道他們內(nèi)部的實(shí)現(xiàn)原理呢?接下來(lái)小編就帶大家進(jìn)入主題,希望能幫助到你2021-09-09詳解HTML5 使用video標(biāo)簽實(shí)現(xiàn)選擇攝像頭功能
這篇文章主要介紹了詳解HTML5 使用video標(biāo)簽實(shí)現(xiàn)選擇攝像頭功能的相關(guān)資料,希望通過(guò)本文能幫助到大家,實(shí)現(xiàn)這樣的功能,需要的朋友可以參考下2017-10-10微信小程序 textarea 組件詳解及簡(jiǎn)單實(shí)例
這篇文章主要介紹了微信小程序 textarea 組件詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-01-01微信小程序 動(dòng)態(tài)綁定事件并實(shí)現(xiàn)事件修改樣式
這篇文章主要介紹了微信小程序 動(dòng)態(tài)綁定事件并實(shí)現(xiàn)事件修改樣式的相關(guān)資料,需要的朋友可以參考下2017-04-04