首頁 > 軟體

JavaScript 物件管家 Proxy

2023-03-11 06:01:17

正文

JavaScript 在 ES6 中,引入了一個新的物件型別 Proxy,它可以用來代理另一個物件,並可以在代理過程中攔截、覆蓋和客製化物件的操作。Proxy 物件封裝另一個物件並充當中間人,其提供了一個捕捉器函數,可以在代理物件上攔截所有的操作,包括存取屬性、賦值屬性、函數呼叫等等。通過攔截這些操作,可以對代理物件進行客製化和控制。

在開始介紹 Proxy 物件前先了解 3 個術語:

  • target 目標物件:要代理的物件或函數。
  • handler 處理程式:對代理的物件或函數執行某些操作的函數。
  • traps 捕捉器:這些是一些用於處理目標的函數。單擊此處閱讀有關陷阱的更多資訊。

語法

Proxy 物件的基本語法如下:

new Proxy(target, handler);

其中,target 是被代理的目標物件,handler 是一個物件,它包含了一些捕捉器函數,用來攔截代理物件的操作。

下面是一些常見的攔截操作和對應的捕捉器函數:

物件方法

  • getPrototypeOf()Object.getPrototypeOf 方法的捕捉器。
  • setPrototypeOf()Object.setPrototypeOf 方法的捕捉器。
  • isExtensible()Object.isExtensible 方法的捕捉器。
  • preventExtensions()Object.preventExtensions 方法的捕捉器。
  • getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor 方法的捕捉器。
  • handler.defineProperty()Object.defineProperty 方法的捕捉器。

屬性獲取器/設定器

  • get(target, propKey, receiver):攔截物件的讀取屬性操作,返回屬性值。
  • set(target, propKey, value, receiver):攔截物件的設定屬性操作,返回一個布林值表示是否設定成功。
  • has(target, propKey):攔截物件的 in 操作符,返回一個布林值表示物件是否包含該屬性。
  • deleteProperty(target, propKey):攔截物件的 delete 操作符,返回一個布林值表示是否刪除成功。
  • ownKeys()Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的捕捉器

函數方法

如果目標物件是一個函數,可以使用下面 2 個捕捉器。

  • apply(target, thisArg, args):攔截函數的呼叫操作,返回撥用結果。
  • construct(target, args, newTarget):攔截 new 操作符,返回一個物件。

Proxy 在目標物件周圍建立一個不可檢測的屏障,將所有操作重定向到處理程式物件。如果傳送一個空的 handler ,代理只是原始物件的一個空包裝器。

const author = {
    name: "Quintion",
    age: 36,
};
const proxyAuthor = new Proxy(author, {});
console.log(author.name); // Quintion
console.log(proxyAuthor.name); // Quintion

為了賦予代理意義,需要向處理程式新增一些操作方法。

捕捉器

每當與一個物件互動時,都在呼叫一個內部方法。代理允許使用捕捉器攔截給定內部方法的執行。

因此,當執行 author.name 時,告訴 JavaScript 引擎呼叫內部 [[GET]] 方法來檢索 name 屬性。當執行 proxyAuthor.name 時,get 捕捉器會呼叫處理程式中定義的 get() 函數來執行,然後再將呼叫傳送到原始物件。

get

get() 方法有兩個必需的引數:

  • target — 傳遞給代理的物件。
  • property — 存取的屬性的名稱。

要自定義代理,在處理程式物件上定義函數。下面定義了 get 方法來記錄存取:

const handler = {
    get(target, property) {
        console.log(`捕捉器 GET:${property}`);
        return target[property];
    },
};

為了讓呼叫通過,捕捉器 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);

執行後,將列印以下內容:

捕捉器 GET[name]
Quintion

set

set 捕捉器用於給目標物件進行賦值操作,返回值是一個布林值。set 捕捉器需要的引數如下:

  • target — 傳遞給代理的物件。
  • property — 將被設定的屬性名或 Symbol。
  • value — 新的屬性值
  • receiver — 最初被呼叫的物件。

下面通過 set 捕捉器驗證年齡值的輸入:

const handler = {
    set(target, property, value) {
        if (property === "age" && typeof value !== "number") {
            throw new TypeError("年齡必須是一個數位");
        }
        target[property] = value;
        return true;
    },
};

下面嘗試將錯誤的型別值賦值給 age ,則會丟擲錯誤:

const proxyAuthor = new Proxy(author, handler);
proxyAuthor.age = "young";
// 執行後丟擲異常:throw new TypeError("年齡必須是一個數位");

set() 方法應該返回一個布林值 true 用來表示賦值成功。 在嚴格模式下執行,並且返回一個假值或什麼都不返回,則會丟擲錯誤。

除了攔截對屬性的讀取和修改,Proxy 總共可以攔截 13 種操作。

應用場景

通過 Proxy 物件的特徵,可以將其使用在下面這些場合:

驗證和過濾

代理Proxy 用於攔截和驗證對物件屬性的存取。如,可以建立一個代理來檢查使用者輸入的資料是否符合預期的格式,並拒絕不正確的資料。就如下面 age 屬性賦值判斷

快取

代理Proxy 用於快取物件的操作結果,以避免重複計算。如,可以建立一個代理來攔截物件的某些方法,並將結果儲存在快取中,以便將來使用。

下面是一個基於 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 類,該類中包含一個內部的 Map 物件用於儲存快取資料,並且定義了一個 proxy 物件作為該類的代理。

proxy 物件的 get 方法中,根據傳入的屬性名返回相應的方法。如果屬性名為 get,則返回一個可以獲取快取值的方法;如果屬性名為 set,則返回一個可以設定快取值的方法;如果屬性名為 has,則返回一個可以判斷是否存在快取值的方法;如果屬性名為 delete,則返回一個可以刪除快取值的方法。

下面是一個使用該快取庫的範例:

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

在上面的程式碼中,建立了一個 Cache 物件,並呼叫其 set 方法設定快取值,然後呼叫其 get 方法獲取快取值,並呼叫其 has 方法判斷快取值是否存在,最後呼叫其 delete 方法刪除快取值。

監聽屬性變化

代理Proxy用於監視物件屬性的變化,並在屬性發生變化時觸發其他操作。如,建立一個代理來監視物件屬性的變化,並在屬性發生變化時更新頁面上的元素。

防止誤操作

代理Proxy用於防止誤操作,如,建立一個代理來攔截物件的某些方法,並在方法呼叫時檢查一些條件,以確保方法只在正確的上下文中呼叫。

虛擬化

代理Proxy可以用於建立虛擬化物件。如,建立一個代理物件,用於代替某個物件的真實實現,並且在實際物件執行之前,對其進行修改或攔截。

總結

上面介紹瞭如何使用代理Proxy物件來監視物件,通過使用處理程式物件中的捕捉器方法向它們新增自定義行為,提供更高階的物件操作和控制功能,從而增強程式碼的可讀性和可維護性。

以上就是JavaScript 物件管家 Proxy的詳細內容,更多關於JavaScript物件Proxy的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com