欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS?中Proxy代理和?Reflect反射方法示例詳解

 更新時間:2022年10月11日 14:47:24   作者:forwardXX  
這篇文章主要為大家介紹了JS?中Proxy代理和?Reflect反射方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

總所周知,Vue2 => Vue3 時,數(shù)據響應式方法從Object.defineProperty()方法變成了Proxy(),所以今天與大家 Proxy(代理)和 Reflect(反射)的知識。

講解 Proxy 和 Reflect 前,我們需要先了解屬性描述符的作用,所以我們線簡單解釋一下屬性描述符的知識。

1.屬性描述符

屬性描述符(Property Descriptor) 本質上是一個 JavaScript 普通對象,用于描述一個屬性的相關信息,共有下面這幾種屬性。

  • value:屬性值
  • configurable:該屬性的描述符是否可以修改
  • enumerable:該屬性是否可以被枚舉
  • writable:該屬性是否可以被重新賦值
  • 存取器屬性:屬性描述符中如果配置了 get 和 set 中的任何一個,則該屬性不再是一個普通屬性,而變成了存取器屬性。
    • get()讀值函數(shù):如果一個屬性是存取器屬性,則讀取該屬性時,會運行 get 方法,并將 get 方法得到的返回值作為屬性值
    • set(newVal)存值函數(shù):如果給該屬性賦值,則會運行 set 方法,newVal 參數(shù)為賦值的值。

存取器屬性最大的意義,在于可以控制屬性的讀取和賦值,在函數(shù)里可以進行各種操作。

Vue2 數(shù)據響應式就是使用了這一點,在 getter 和 setter 函數(shù)中進行了數(shù)據綁定與派發(fā)更新。

注意點:value 和 writable 屬性不能與 get 和 set 屬性二者不可共存,二者只能選其一。

查看某個對象的屬性描述符,使用以下這兩種方法:

Object.getOwnPropertyDescriptor(對象, 屬性名); //得到一個對象的某個屬性的屬性描述符
Object.getOwnPropertyDescriptors(對象); //得到某個對象的所有屬性描述符

為某個對象添加屬性時 或 修改屬性時,配置其屬性描述符,使用以下這兩種方法:

Object.defineProperty(對象, 屬性名, 描述符); //設置一個對象的某個屬性
Object.defineProperties(對象, 多個屬性的描述符); //設置一個對象的多個屬性

2.Reflect

Reflect 是什么? Reflect 是一個內置的 JS 對象,它提供了一系列方法,可以讓開發(fā)者通過調用這些方法,訪問一些 JS 底層功能。

由于它類似于其他語言的反射,因此取名為 Reflect。

它可以做什么? 使用 Reflect 可以實現(xiàn)諸如:屬性的賦值與取值、調用普通函數(shù)、調用構造函數(shù)、判斷屬性是否存在與對象中 等等功能。

這些功能不是已經存在了嗎?為什么還需要用 Reflect 實現(xiàn)一次? 有一個重要的理念,在 ES5 就被提出:減少魔法、讓代碼更加純粹(語言的方法使用 API 實現(xiàn),而不使用特殊語法實現(xiàn)),這種理念很大程度上是受到函數(shù)式編程的影響。 ES6 進一步貫徹了這種理念,它認為,對屬性內存的控制、原型鏈的修改、函數(shù)的調用等等,這些都屬于底層實現(xiàn),屬于一種魔法,因此,需要將它們提取出來,形成一個正常的 API,并高度聚合到某個對象中,于是就造就了 Reflect 對象。 因此,你可以看到 Reflect 對象中有很多的 API 都可以使用過去的某種語法或其他 API 實現(xiàn)。

Reflect 里面提供了哪些 API 呢?

Reflect API用處等同于
Reflect.get(target, propertyKey)讀取對象 target 的屬性 propertyKey對象的屬性值讀取操作
Reflect.set(target, propertyKey, value)設置對象 target 的屬性 propertyKey 的值為 value對象的屬性賦值操作
Reflect.has(target, propertyKey)判斷一個對象是否擁有一個屬性in 操作符
Reflect.defineProperty(target, propertyKey, attributes)類似于 Object.defineProperty,不同的是如果配置出現(xiàn)問題,返回 false 而不是報錯Object.defineProperty
Reflect.deleteProperty(target, propertyKey)刪除一個對象的屬性delete 操作符
Reflect.apply(target, thisArgument, argumentsList)調用一個指定的函數(shù),并綁定 this 和參數(shù)列表函數(shù)調用操作
Reflect.construct(target, argumentsList)用構造函數(shù)的方式創(chuàng)建一個對象new 操作符

其他更多的 Reflect API

3.Proxy

ECMAScript 6 新增的代理和反射為開發(fā)者提供了攔截并向基本操作嵌入額外行為的能力

具體地說,可以給目標對象(target)定義一個關聯(lián)的代理對象,而這個代理對象可當作一個抽象的目標對象來使用。

因此在對目標對象的各種操作影響到目標對象之前,我們可以在代理對象中對這些操作加以控制,并且最終也可能會改變操作返回的結果。

所以我的理解是:代理(Proxy)能使我們開發(fā)者擁有一種間接修改底層方法的能力,從而控制用戶的操作。

3.1 創(chuàng)建空代理

最簡單的代理是空代理,即除了作為一個抽象的目標對象,什么也不做。 默認情況下,在代理對象上執(zhí)行的所有操作都會無障礙地傳播到目標對象。因此,在任何可以使用目標對象的地方,都可以通過同樣的方式來使用與之關聯(lián)的代理對象。

代理是使用 Proxy 構造函數(shù)創(chuàng)建的,這個構造函數(shù)接收兩個參數(shù):目標對象和處理程序對象。缺 少其中任何一個參數(shù)都會拋出 TypeError。返回一個代理對象 如:new Proxy(target, handler);

要創(chuàng)建空代理,可以傳一個簡單的對象字面量作為處理程序對象,從而讓所有操作暢通無阻地抵達目標對象。

const target = {
 id: 'target'
}; //target:目標對象
const handler = {}; //handler:是一個普通對象,其中可以重寫底層實現(xiàn)
//創(chuàng)建空對象
const proxy = new Proxy(target, handler);
// id 屬性會訪問同一個值
console.log(target.id); // target
console.log(proxy.id); // target
// 給目標屬性賦值會反映在兩個對象上 因為兩個對象訪問的是同一個值
target.id = 'foo';
console.log(target.id); // foo
console.log(proxy.id); // foo
// 給代理屬性賦值會反映在兩個對象上 因為這個賦值會轉移到目標對象
proxy.id = 'bar';
console.log(target.id); // bar
console.log(proxy.id); // bar
// hasOwnProperty()方法在兩個地方  也都會應用到目標對象
console.log(target.hasOwnProperty('id')); // true
console.log(proxy.hasOwnProperty('id')); // true
// Proxy.prototype 是 undefined   因此不能使用 instanceof 操作符
console.log(target instanceof Proxy); // TypeError: Function has non-object prototype
'undefined' in instanceof check
console.log(proxy instanceof Proxy); // TypeError: Function has non-object prototype
'undefined' in instanceof check
// 嚴格相等可以用來區(qū)分代理和目標
console.log(target === proxy); // false

3.2 定義捕獲器

使用代理的主要目的是可以定義捕獲器(trap)。捕獲器就是在處理程序對象中定義的“基本操作的攔截器”。

每個處理程序對象可以包含零個或多個捕獲器,每個捕獲器都對應一種基本操作,可以直接或間接在代理對象上調用。

每次在代理對象上調用這些基本操作時,代理可以在這些操作傳播到目標對象之前先調用捕獲器函數(shù),從而攔截并修改相應的行為。

所有捕獲器都可以訪問相應的參數(shù),基于這些參數(shù)可以重建被捕獲方法的原始行為。比如,get()捕獲器會接收到目標對象、要查詢的屬性代理對象三個參數(shù)。

const target = {
  foo: "bar",
};
const handler = {
  // 捕獲器在處理程序對象中以方法名為鍵
  get(trapTarget, property, receiver) {
    //trapTarget - 目標對象
    //property   - 要查詢的屬性
    //receiver   - 代理對象
    return "handler override";
  },
};
const proxy = new Proxy(target, handler);
console.log(target.foo); // bar
console.log(proxy.foo); // handler override

3.3 捕獲器不變式

使用捕獲器幾乎可以改變所有基本方法的行為,但也不是沒有限制。

根據 ECMAScript 規(guī)范,每個捕獲的方法都知道目標對象上下文、捕獲函數(shù)簽名,而捕獲處理程序的行為必須遵循“捕獲器不變式”(trap invariant)。捕獲器不變式因方法不同而異,但通常都會防止捕獲器定義出現(xiàn)過于反常的行為。

比如,如果目標對象有一個不可配置且不可寫的數(shù)據屬性,那么在捕獲器返回一個與該屬性不同的值時,會拋出 TypeError:

const target = {};
Object.defineProperty(target, "foo", {
  configurable: false,
  writable: false,
  value: "bar",
});
const handler = {
  get() {
    return "qux";
  },
};
const proxy = new Proxy(target, handler);
console.log(proxy.foo); // TypeError

3.4 可撤銷代理

有時候可能需要中斷代理對象與目標對象之間的聯(lián)系。

Proxy 也暴露了 revocable()方法,這個方法支持撤銷代理對象與目標對象的關聯(lián)。

后續(xù)可直接調用撤銷函數(shù) revoke() 來撤銷代理。

撤銷代理之后再調用代理會拋出 TypeError,撤銷函數(shù)和代理對象是在實例化時同時生成的:

const target = {
  foo: "bar",
};
const handler = {
  get() {
    return "intercepted";
  },
};
const { proxy, revoke } = Proxy.revocable(target, handler);
console.log(proxy.foo); // intercepted
console.log(target.foo); // bar
revoke();
console.log(proxy.foo); // TypeError

4.代理捕獲器與反射方法

4.1 get()

get()捕獲器會在獲取屬性值的操作中被調用。對應的反射 API 方法為 Reflect.get()

const myTarget = {};
const proxy = new Proxy(myTarget, {
  get(target, property, receiver) {
    console.log("get()");
    return Reflect.get(...arguments);
  },
});
proxy.foo; // 觸發(fā)get()捕獲器

返回值 返回值無限制。

攔截的操作

  • proxy.property
  • proxy[property]
  • Object.create(proxy)[property]
  • Reflect.get(proxy, property, receiver)

捕獲器處理程序參數(shù)

  • target:目標對象。
  • property:引用的目標對象上的字符串鍵屬性。① - receiver:代理對象或繼承代理對象的對象。

捕獲器不變式 如果 target.property 不可寫且不可配置,則處理程序返回的值必須與 target.property 匹配。 如果 target.property 不可配置且[[Get]]特性為 undefined,處理程序的返回值也必須是 undefined。

4.2 set()

set()捕獲器會在設置屬性值的操作中被調用。對應的反射 API 方法為 Reflect.set()。

const myTarget = {};
const proxy = new Proxy(myTarget, {
  set(target, property, value, receiver) {
    console.log("set()");
    return Reflect.set(...arguments);
  },
});
proxy.foo = "bar"; // 觸發(fā)set()捕獲器

返回值 返回 true 表示成功;返回 false 表示失敗,嚴格模式下會拋出 TypeError。

攔截的操作

  • proxy.property = value
  • proxy[property] = value
  • Object.create(proxy)[property] = value
  • Reflect.set(proxy, property, value, receiver)

捕獲器處理程序參數(shù)

  • target:目標對象。
  • property:引用的目標對象上的字符串鍵屬性。
  • value:要賦給屬性的值。
  • receiver:接收最初賦值的對象。

捕獲器不變式 如果 target.property 不可寫且不可配置,則不能修改目標屬性的值。 如果 target.property 不可配置且[[Set]]特性為 undefined,則不能修改目標屬性的值。 在嚴格模式下,處理程序中返回 false 會拋出 TypeError。

4.3 has()

has()捕獲器會在 in 操作符中被調用。對應的反射 API 方法為 Reflect.has()。

const myTarget = {};
const proxy = new Proxy(myTarget, {
  has(target, property) {
    console.log("has()");
    return Reflect.has(...arguments);
  },
});
"foo" in proxy; //觸發(fā) has()捕獲器

返回值 has()必須返回布爾值,表示屬性是否存在。返回非布爾值會被轉型為布爾值。

攔截的操作

  • property in proxy
  • property in Object.create(proxy)
  • with(proxy) {(property);}
  • Reflect.has(proxy, property)

捕獲器處理程序參數(shù)

  • target:目標對象。
  • property:引用的目標對象上的字符串鍵屬性。

捕獲器不變式 如果 target.property 存在且不可配置,則處理程序必須返回 true。 如果 target.property 存在且目標對象不可擴展,則處理程序必須返回 true。

4.4 deleteProperty()

deleteProperty()捕獲器會在 delete 操作符中被調用。對應的反射 API 方法為 Reflect.deleteProperty()。

const myTarget = {};
const proxy = new Proxy(myTarget, {
  deleteProperty(target, property) {
    console.log("deleteProperty()");
    return Reflect.deleteProperty(...arguments);
  },
});
delete proxy.foo; // 觸發(fā)deleteProperty()捕獲器
  • 返回值 deleteProperty()必須返回布爾值,表示刪除屬性是否成功。返回非布爾值會被轉型為布爾值。
  • 攔截的操作
    • delete proxy.property
    • delete proxy[property]
    • Reflect.deleteProperty(proxy, property)
  • 捕獲器處理程序參數(shù)
    • target:目標對象。
    • property:引用的目標對象上的字符串鍵屬性。
  • 捕獲器不變式 如果自有的 target.property 存在且不可配置,則處理程序不能刪除這個屬性。

4.5 apply()

apply()捕獲器會在調用函數(shù)時中被調用。對應的反射 API 方法為 Reflect.apply()。

const myTarget = () => {};
const proxy = new Proxy(myTarget, {
  apply(target, thisArg, ...argumentsList) {
    console.log("apply()");
    return Reflect.apply(...arguments);
  },
});
proxy(); // 觸發(fā)apply()捕獲器
  • 返回值 返回值無限制。
  • 攔截的操作
    • proxy(...argumentsList)
    • Function.prototype.apply(thisArg, argumentsList)
    • Function.prototype.call(thisArg, ...argumentsList)
    • Reflect.apply(target, thisArgument, argumentsList)
  • 捕獲器處理程序參數(shù)
    • target:目標對象。
    • thisArg:調用函數(shù)時的 this 參數(shù)。
    • argumentsList:調用函數(shù)時的參數(shù)列表
  • 捕獲器不變式 target 必須是一個函數(shù)對象。

4.6 construct()

construct()捕獲器會在 new 操作符中被調用。對應的反射 API 方法為 Reflect.construct()。

const myTarget = function () {};
const proxy = new Proxy(myTarget, {
  construct(target, argumentsList, newTarget) {
    console.log("construct()");
    return Reflect.construct(...arguments);
  },
});
new proxy(); // 觸發(fā)construct()捕獲器
  • 返回值 construct()必須返回一個對象。
  • 攔截的操作
    • new proxy(...argumentsList)
    • Reflect.construct(target, argumentsList, newTarget)
  • 捕獲器處理程序參數(shù)
    • target:目標構造函數(shù)
    • argumentsList:傳給目標構造函數(shù)的參數(shù)列表。
    • newTarget:最初被調用的構造函數(shù)。
  • 捕獲器不變式 target 必須可以用作構造函數(shù)。

還有另外七種捕獲器:

  • defineProperty()捕獲器會在 Object.defineProperty()中被調用。
  • getOwnPropertyDescriptor()捕獲器會在 Object.getOwnPropertyDescriptor()中被調 用。
  • ownKeys()捕獲器會在 Object.keys()及類似方法中被調用。
  • getPrototypeOf()捕獲器會在 Object.getPrototypeOf()中被調用。
  • setPrototypeOf()捕獲器會在 Object.setPrototypeOf()中被調用。
  • isExtensible()捕獲器會在 Object.isExtensible()中被調用。
  • preventExtensions()捕獲器會在 Object.preventExtensions()中被調用。

這七種捕獲器詳細介紹可參考MDN - Proxy。

參考博客

《Javascript 高級程序設計(第 4 版)》(JS 紅寶書)

MDN - Proxy

MDN - Reflect

以上就是JS 中Proxy代理和 Reflect反射方法示例詳解的詳細內容,更多關于JS Proxy代理Reflect反射的資料請關注腳本之家其它相關文章!

相關文章

  • JavaScript事件詳細講解

    JavaScript事件詳細講解

    本文給大家介紹js事件詳解,涉及到事件流,事件處理,事件對象等方面的知識,非常不錯,具有參考借鑒價值,感興趣的朋友一起學習吧
    2016-06-06
  • Typescript3.9 常用新特性一覽(推薦)

    Typescript3.9 常用新特性一覽(推薦)

    這篇文章主要介紹了Typescript3.9 常用新特性一覽,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-05-05
  • javascript 對象比較實現(xiàn)代碼

    javascript 對象比較實現(xiàn)代碼

    js對象比較實現(xiàn)代碼。
    2009-04-04
  • js對象淺拷貝和深拷貝詳解

    js對象淺拷貝和深拷貝詳解

    這篇文章主要為大家詳細介紹了JavaScript對象的淺拷貝和深拷貝代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • 三分鐘帶你快速學會微信小程序的條件渲染

    三分鐘帶你快速學會微信小程序的條件渲染

    所謂的條件渲染就是判斷是否需要把代碼渲染到展示頁面上,下面這篇文章主要給大家介紹了關于微信小程序條件渲染的相關資料,文中通過實例代碼和圖文介紹的非常詳細,需要的朋友可以參考下
    2022-08-08
  • Javascript讀取json文件方法實例總結

    Javascript讀取json文件方法實例總結

    json文件是一種輕量級的數(shù)據交互格式,下面這篇文章主要給大家介紹了關于Javascript讀取json文件方法的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2022-11-11
  • javascript 函數(shù)聲明與函數(shù)表達式的區(qū)別介紹

    javascript 函數(shù)聲明與函數(shù)表達式的區(qū)別介紹

    javascript中的函數(shù)聲明與函數(shù)表達式使用比較頻繁,可能很多的朋友都不知道他們之間的區(qū)別,在此為大家詳細介紹下,希望對大家有所幫助
    2013-10-10
  • 深入理解Javascript作用域與變量提升

    深入理解Javascript作用域與變量提升

    這篇文章主要是對Javascript作用域與變量提升進行了詳細的分析介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • js獲取光標位置的最新方法

    js獲取光標位置的最新方法

    這篇文章主要給大家介紹了關于js獲取光標位置的最新方法,獲取光標位置,最常用的方法就是使用Selection對象和Range對象,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2023-09-09
  • Code:loadScript( )加載js的功能函數(shù)

    Code:loadScript( )加載js的功能函數(shù)

    Code:loadScript( )加載js的功能函數(shù)...
    2007-02-02

最新評論