專業(yè)做化妝品外包材的招聘網(wǎng)站seo技術(shù)團(tuán)隊
JavaScript 在 ES6 中,引入了一個新的對象類型?Proxy
,它可以用來代理另一個對象,并可以在代理過程中攔截、覆蓋和定制對象的操作。Proxy
?對象封裝另一個對象并充當(dāng)中間人,其提供了一個捕捉器函數(shù),可以在代理對象上攔截所有的操作,包括訪問屬性、賦值屬性、函數(shù)調(diào)用等等。通過攔截這些操作,可以對代理對象進(jìn)行定制和控制。
在開始介紹?Proxy
?對象前先了解 3 個術(shù)語:
target 目標(biāo)對象
:要代理的對象或函數(shù)。handler 處理程序
:對代理的對象或函數(shù)執(zhí)行某些操作的函數(shù)。traps 捕捉器
:這些是一些用于處理目標(biāo)的函數(shù)。單擊此處閱讀有關(guān)陷阱的更多信息。
語法
Proxy
?對象的基本語法如下:
new Proxy(target, handler);
其中,target
?是被代理的目標(biāo)對象,handler
?是一個對象,它包含了一些捕捉器函數(shù),用來攔截代理對象的操作。
下面是一些常見的攔截操作和對應(yīng)的捕捉器函數(shù):
對象方法
getPrototypeOf()
:Object.getPrototypeOf
?方法的捕捉器。setPrototypeOf()
:Object.setPrototypeOf
?方法的捕捉器。isExtensible()
:Object.isExtensible
?方法的捕捉器。preventExtensions()
:Object.preventExtensions
?方法的捕捉器。getOwnPropertyDescriptor()
:Object.getOwnPropertyDescriptor
?方法的捕捉器。handler.defineProperty()
:Object.defineProperty
?方法的捕捉器。
屬性獲取器/設(shè)置器
get(target, propKey, receiver)
:攔截對象的讀取屬性操作,返回屬性值。set(target, propKey, value, receiver)
:攔截對象的設(shè)置屬性操作,返回一個布爾值表示是否設(shè)置成功。has(target, propKey)
:攔截對象的?in
?操作符,返回一個布爾值表示對象是否包含該屬性。deleteProperty(target, propKey)
:攔截對象的?delete
?操作符,返回一個布爾值表示是否刪除成功。ownKeys()
:Object.getOwnPropertyNames
?方法和?Object.getOwnPropertySymbols
?方法的捕捉器
函數(shù)方法
如果目標(biāo)對象是一個函數(shù),可以使用下面 2 個捕捉器。
apply(target, thisArg, args)
:攔截函數(shù)的調(diào)用操作,返回調(diào)用結(jié)果。construct(target, args, newTarget)
:攔截?new
?操作符,返回一個對象。
Proxy
?在目標(biāo)對象周圍創(chuàng)建一個不可檢測的屏障,將所有操作重定向到處理程序?qū)ο?。如果發(fā)送一個空的?handler
?,代理只是原始對象的一個空包裝器。
const author = {name: "Quintion",age: 36,
};const proxyAuthor = new Proxy(author, {});console.log(author.name); // Quintion
console.log(proxyAuthor.name); // Quintion
為了賦予代理意義,需要向處理程序添加一些操作方法。
捕捉器
每當(dāng)與一個對象交互時,都在調(diào)用一個內(nèi)部方法。代理允許使用捕捉器攔截給定內(nèi)部方法的執(zhí)行。
因此,當(dāng)運(yùn)行?author.name
?時,告訴 JavaScript 引擎調(diào)用內(nèi)部?[[GET]]
?方法來檢索?name
?屬性。當(dāng)運(yùn)行?proxyAuthor.name
?時,get
?捕捉器會調(diào)用處理程序中定義的?get()
?函數(shù)來執(zhí)行,然后再將調(diào)用發(fā)送到原始對象。
get
get()
?方法有兩個必需的參數(shù):
target
?— 傳遞給代理的對象。property
?— 訪問的屬性的名稱。
要自定義代理,在處理程序?qū)ο笊隙x函數(shù)。下面定義了?get
?方法來記錄訪問:
const handler = {get(target, property) {console.log(`捕捉器 GET:${property}`);return target[property];},
};
為了讓調(diào)用通過,捕捉器?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)對象進(jìn)行賦值操作,返回值是一個布爾值。set
?捕捉器需要的參數(shù)如下:
target
?— 傳遞給代理的對象。property
?— 將被設(shè)置的屬性名或 Symbol。value
?— 新的屬性值receiver
?— 最初被調(diào)用的對象。
下面通過?set
?捕捉器驗證年齡值的輸入:
const handler = {set(target, property, value) {if (property === "age" && typeof value !== "number") {throw new TypeError("年齡必須是一個數(shù)字");}target[property] = value;return true;},
};
下面嘗試將錯誤的類型值賦值給?age
?,則會拋出錯誤:
const proxyAuthor = new Proxy(author, handler);proxyAuthor.age = "young";
// 執(zhí)行后拋出異常:throw new TypeError("年齡必須是一個數(shù)字");
set()
?方法應(yīng)該返回一個布爾值?true
?用來表示賦值成功。 在嚴(yán)格模式下運(yùn)行,并且返回一個假值或什么都不返回,則會拋出錯誤。
除了攔截對屬性的讀取和修改,Proxy
?總共可以攔截?13?種操作。
應(yīng)用場景
通過?Proxy
?對象的特征,可以將其使用在下面這些場合:
驗證和過濾
代理Proxy
?用于攔截和驗證對對象屬性的訪問。如,可以創(chuàng)建一個代理來檢查用戶輸入的數(shù)據(jù)是否符合預(yù)期的格式,并拒絕不正確的數(shù)據(jù)。就如下面?age
?屬性賦值判斷
緩存
代理Proxy
?用于緩存對象的操作結(jié)果,以避免重復(fù)計算。如,可以創(chuàng)建一個代理來攔截對象的某些方法,并將結(jié)果存儲在緩存中,以便將來使用。
下面是一個基于 Proxy 的緩存庫的示例:
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);};}},});}
}
在上面的代碼中,定義了一個?Cache
?類,該類中包含一個內(nèi)部的?Map
?對象用于存儲緩存數(shù)據(jù),并且定義了一個?proxy
?對象作為該類的代理。
在?proxy
?對象的?get
?方法中,根據(jù)傳入的屬性名返回相應(yīng)的方法。如果屬性名為?get
,則返回一個可以獲取緩存值的方法;如果屬性名為?set
,則返回一個可以設(shè)置緩存值的方法;如果屬性名為?has
,則返回一個可以判斷是否存在緩存值的方法;如果屬性名為?delete
,則返回一個可以刪除緩存值的方法。
下面是一個使用該緩存庫的示例:
const cacheHelper = new Cache();cacheHelper.set("foo", "bar");
console.log(cacheHelper.get("foo")); // "bar"
console.log(cacheHelper.has("foo")); // truecacheHelper.delete("foo");
console.log(cacheHelper.get("foo")); // undefined
console.log(cacheHelper.has("foo")); // false
在上面的代碼中,創(chuàng)建了一個?Cache
?對象,并調(diào)用其?set
?方法設(shè)置緩存值,然后調(diào)用其?get
?方法獲取緩存值,并調(diào)用其 has 方法判斷緩存值是否存在,最后調(diào)用其?delete
?方法刪除緩存值。
監(jiān)聽屬性變化
代理Proxy
用于監(jiān)視對象屬性的變化,并在屬性發(fā)生變化時觸發(fā)其他操作。如,創(chuàng)建一個代理來監(jiān)視對象屬性的變化,并在屬性發(fā)生變化時更新頁面上的元素。
防止誤操作
代理Proxy
用于防止誤操作,如,創(chuàng)建一個代理來攔截對象的某些方法,并在方法調(diào)用時檢查一些條件,以確保方法只在正確的上下文中調(diào)用。
虛擬化
代理Proxy
可以用于創(chuàng)建虛擬化對象。如,創(chuàng)建一個代理對象,用于代替某個對象的真實實現(xiàn),并且在實際對象執(zhí)行之前,對其進(jìn)行修改或攔截。
總結(jié)
上面介紹了如何使用代理Proxy
對象來監(jiān)視對象,通過使用處理程序?qū)ο笾械牟蹲狡鞣椒ㄏ蛩鼈兲砑幼远x行為,提供更高級的對象操作和控制功能,從而增強(qiáng)代碼的可讀性和可維護(hù)性。