首頁  >  文章  >  web前端  >  JavaScript中Proxy的詳細介紹(程式碼範例)

JavaScript中Proxy的詳細介紹(程式碼範例)

不言
不言轉載
2018-12-10 17:52:199198瀏覽

這篇文章帶給大家的內容是關於JavaScript中Proxy的詳細介紹(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

Proxy 讓我們可以對任何物件的絕大部分行為進行監聽和乾涉,實現更多的自訂程式行為。

用法:new Proxy(target, handler)。

Proxy 透過設定行為監聽方法來擷取程式對對應物件的行為。

    const obj = {};
    const proxy = new Proxy(obj, {
        // ...
    })

Proxy 的建構器接受兩個參數,第一個參數為需要包裝的目標對象,第二個參數則為用於監聽目標對象行為的監聽器,其中監聽器可以接受一些參數以監聽相對應的程序行為。
監聽屬性、參數及監聽內容

屬性值 監聽器參數 監聽內容
has (target, prop) #監聽in 語句的使用
get (target, prop, reciver) 監聽目標物件的屬性讀取
set (target, prop, value, reciver) 監聽目標物件的屬性賦值
deleteProperty (target, prop) 監聽delete 語句對目標對象的刪除屬性行為
ownKeys (target) 監聽Object.getOwnPropertyName() 的讀取
#apply (target, thisArg, arguments) 監聽目標函數(作為目標物件)的呼叫行為
construct (target, arguments, newTarget) 監聽目標建構子(作為目標物件)利用new 而產生實例的行為
getPrototypeOf (target) 監聽Objext.getPrototypeOf() 的讀取
setPrototypeOf (target, prototype) #監聽Objext.setPrototypeOf() 的呼叫
isExtensible (target) 監聽Objext.isExtensible() 的讀取
preventExtensions (target) 監聽Objext.preventExtensions() 的讀取
getOwnPropertyDescriptor (target, prop) 監聽Objext.getOwnPropertyDescriptor() 的呼叫
defineProperty (target, property, descriptor) 監聽Object.defineProperty() 的呼叫

has

可以透過為Proxy 的handler 定義has 監聽方法,來監聽程式透過in 語句來檢查一個字串或數字是否為該Proxy 的目標物件中某個屬性的屬性鍵的過程。

const p = new Proxy({}, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return true;
    }
})

console.log('foo' in p);
// Checking "foo" is in the target or not
// true

此監聽方法有兩個需要注意的地方,如果遇到這兩種情況,便會拋出 TypeError 錯誤。

1、當目標物件被其他程式透過Object.preventExtensions() 停用了屬性拓展(該物件無法再增加新的屬性,只能對目前已有的屬性進行操作,包括讀取、操作和刪除,但是一旦刪除就無法再定義) 功能,且被檢查的屬性鍵確實存在與目標物件中,該監聽方法便不能回傳false。

const obj = {foo: 1};

Object.preventExtensions(obj);

const p = new Proxy(obj, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return false; 
    }
})

console.log('foo' in p);   
//抛出Uncaught TypeError:

2.當被檢查的屬性鍵存在與目標物件中,且該屬性的 configurable 設定為 false 時,此監聽方法不能傳回 false。

const obj = {};

Object.defineProperty(obj, 'foo', {
    configurable: false,
    value: 10
})

const p = new Proxy(obj, {
    has(target, prop){
        console.log(`Checking "${prop}" is in the target or not`);
        return false;
    }
})

console.log('foo' in p);
//抛出Uncaught TypeError:

get

Getter只能對已知的屬性鍵進行監聽,而無法對所有屬性讀取行為進行攔截,而Proxy 可以透過設定get 監聽方法,攔截和乾涉目標物件的所有屬性讀取行為。

const obj = {foo: 1};
const p = new Proxy(obj, {
    get(target, prop){
        console.log(`Program is trying to fetch the property "${prop}".`);
        return target[prop];
    }
})

alert(p.foo);  // Program is trying to fetch the property "foo".
alert(p.something);    // Program is trying to fetch the property "something".

  這個監聽方法也存在需要注意的地方-當目標物件被讀取屬性的configurable 和writable 屬性都為false 時,監聽方法最後傳回的值必須與目標物件的原始屬性值一致。

const obj = {};

Object.defineProperty(obj, 'foo', {
    configurable: false,
    value: 10,
    writable: false
})

const p = new Proxy(obj, {
    get(target, prop){
        return 20;
    }
})

console.log(p.foo);

set

  handler.set 用於監聽目標物件的所有屬性賦值行為。注意,如果目標物件本身的某個屬性是不可寫也不可配置的,那麼 set 不得改變這個屬性的值,只能傳回同樣的值,否則報錯。

const obj = {};
const p = new Proxy(obj, {
    set(target, prop, value){
        console.log(`Setting value "${value}" on the key "${prop}" in the target object`);
        target[prop] = value;
        return true;
    }
})

p.foo = 1;  
// Setting value "1" on the key "foo" in the target object

apply

handler.apply , Proxy 也為作為目標物件的函數提供了監聽其呼叫行為的屬性。

const sum = function(...args) {
  return args
    .map(Number)
    .filter(Boolean)
    .reduce((a, b) => a + b);

}

const p = new Proxy(sum, {
  apply(target, thisArg, args) {
    console.log(`Function is being called with arguments [${args.join()}] and context ${thisArg}`);
    return target.call(thisArg, ...args);
  }
})

console.log(p(1, 2, 3));
// Function is being called with arguments [1,2,3] and context undefined
// 6

construct

  handler.construct, Proxy 也可以將類別作為目標監聽對象,並監聽其透過new 語句來生產新實例的行為,這同樣可以使用再作為建構器的構造函數上。

class Foo{};

const p = new Proxy(Foo, {
    construct(target, args, newTarget){
        return {arguments: args}    // 这里返回的结果会是 new 所得到的实例
    }
});

const obj = new p(1, 2, 3);
console.log(obj.arguments);  // [1, 2, 3]

建立可解除 Proxy 物件

用法:Proxy.revocable(target, handler) : (proxy, revoke)。

const obj = {foo: 10};
const revocable = Proxy.revocable(obj, {
    get(target, prop){
        return 20;
    }
})
const proxy = revocable.proxy;
console.log(proxy.foo); // 20
revocable.revoke();
console.log(proxy.foo); 
// TypeError: Cannot perform 'get' on a proxy that has been revoked

Proxy.revocable(target, handler) 會傳回一個有兩個屬性的對象,其中一個proxy 便是該函數所產生的可解除Proxy 對象,而另一個revoke 則是將剛才的Proxy 物件解除的解除方法。

#

以上是JavaScript中Proxy的詳細介紹(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除