日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

深入浅出ES6的标准内置对象Proxy

發布時間:2023/12/18 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入浅出ES6的标准内置对象Proxy 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Proxy是ES6規范定義的標準內置對象,可以對目標對象的讀取、函數調用等操作進行攔截。一般來說,通過Proxy可以讓目標對象“可控”,比如是否能調用對象的某個方法,能否往對象添加屬性等等。

const originalObj = {name: 'xialei' }; const publicObj = new Proxy(originalObj, {set(target, prop, value) {// 將屬性值轉化為大寫target[prop] = value.toString().toUpperCase();} });publicObj.name = 'xialei'; console.log(publicObj.name); // XIALEI

從上例可以看出Proxy不需要更改目標對象(也就是originalObj),就可以對originalObj的行為進行攔截。

語法

let obj = new Proxy(target, handler);

target Object 目標對象。可以是任何類型的對象,甚至包括原生對象(比如數組,函數,另一個Proxy對象)
handler Object 代理行為對象。訪問目標對象時會自動觸發該handler的對應屬性。

和大多數開發者一樣,剛開始學習Proxy的時候,這個handler不知道是個什么東西,什么時候能觸發。

先看一個簡單的例子,看看handler到底是什么東西。假設我們開發一個游戲腳本,由于內存修改器的盛行,我們需要對內存中的數據進行安全處理,但是不能影響外部使用,我們使用Proxy完成這個功能。

const gameObj = {hp: 0};const publicGameObj = new Proxy(gameObj, {get(target, prop) {return target[prop]/2;},set(target, prop, value) {target[prop] = value*2;}});publicGameObj.hp = 10000;console.log(publicGameObj.hp, gameObj); // 10000 {hp: 20000}

gameObj是我們在內存中真實存儲數據的地方,可以看到HP是20000,但是publicGameObj.hp是10000,外部使用publicGameObj.hp即可(比如UI層展示HP為10000);

例程handler使用到的屬性

get publicGameObj.hp進行了讀取操作,因此會自動觸發handler的get方法
set publicGameObj.hp=10000進行了賦值操作,因此為自動觸發handler的set方法

handler對象

handler對象是Proxy的核心基礎,所有對目標對象的操作都需要通過handler來處理,雖然內容有點多,但是常用的不多。

說明

目標對象 被代理的對象。外部不能直接訪問(當然語法上是可以訪問的,你都用上Proxy了,還訪問他干嘛?)
代理對象 new Proxy的返回值。外部直接訪問。目標對象會作為handler對應函數的參數傳入
帶*號的是常用屬性

所有訪問都是對代理對象訪問才會觸發,直接訪問目標對象不會觸發(代理對象壓根沒參與進來,如果觸發那一定是出bug了)

handler.getPrototypeOf(target)

說明:獲取目標對象的原型

觸發時機:Object.getPrototypeOf(代理對象)

參數:

target Object 目標對象

返回值:

Object 對象的原型

const array = []; const myArray = new Proxy(array, {getPrototypeOf(target) {console.log('讀取對象原型');return Object.getPrototypeOf(array);} }); console.log(Object.getPrototypeOf(myArray)); // 輸出 // 讀取對象原型 // []

handler.setPrototypeOf(target, prototype)

說明:設置對象的原型

觸發時機:Object.setPrototypeOf(代理對象, 原型)
參數:

target Object 目標對象
prototype Object 原型對象或null

返回值:

boolean 設置成功返回true,否則返回false(比如不讓設置)

const array = []; const myArray = new Proxy(array, {setPrototypeOf(target, prototype) {Object.setPrototypeOf(target, prototype);return true;} }); Object.setPrototypeOf(myArray, Object.prototype); console.log(Object.getPrototypeOf(myArray)); // {}

handler.isExtensible(target)

說明:檢測對象是否可擴展(個人理解:也就是能否添加屬性、函數)
觸發時機:Object.isExtensible(代理對象)
參數:

target Object 目標對象

返回參數:

boolean

handler.preventExtensions(target)

說明:設置目標對象為不可擴展
觸發時機:Object.preventExtensions(代理對象)
參數:

target Object 目標對象

返回值:

boolean 設置目標對象不可擴展后返回true,不管是否設置目標對象不可擴展,返回false都會報錯

const obj = {}; const p = new Proxy(obj, {preventExtensions(target) {Object.preventExtensions(target);return true;} });Object.preventExtensions(p);p.a = 1; console.log(p); // {} 目標對象不可擴展,所以a屬性設置不進去

*handler.getOwnPropertyDescriptor(target, prop)

說明:獲取目標對象屬性的描述符

觸發時機:Object.getOwnPropertyDescriptor(代理對象)

參數:

target Object 目標對象
prop <string|Symbol|number> 屬性名

返回參數:

Object 屬性描述符

const obj = {a: 1 }; const p = new Proxy(obj, {getOwnPropertyDescriptor(target, prop) {return target[prop];} });console.log(Object.getOwnPropertyDescriptor(obj, 'a')); // { value: 1, writable: true, enumerable: true, configurable: true }

*handler.defineProperty(target,prop,properties)

說明:在對象上定義屬性(添加新屬性或修改現有屬性)
觸發時機:Object.defineProperty(代理對象,屬性名,屬性描述對象)
參數:

target Object 目標對象
prop string|number|Symbol 屬性名
properties Object 屬性描述對象

返回值:

boolean 定義成功返回true,定義失敗或不允許定義返回false

const obj = {name: 'xialei',name2: 'xx' }; const p = new Proxy(obj, {defineProperty(target, prop, properties) {if (prop === 'name') {Object.defineProperty(target, prop, properties);return true;}return false;} });Object.defineProperty(p, 'name', {value: 'aaa', });Object.defineProperty(p, 'name2', { // TypeErrorvalue: 'aaa', });

*handler.has(target, prop)

說明:判斷對象是否有指定屬性
觸發時機:prop in 代理對象
參數:

target Object 目標對象
prop string|number|Symbol 屬性名

返回值:

boolean

*handler.get(target, prop, receiver)

說明: 屬性讀取器
觸發時機:讀取代理對象的屬性時觸發

參數:

target Object 目標對象
prop string|number|Symbol 屬性名
receiver Proxy 代理對象或者原型鏈上的代理對象

返回值:

任何值

const obj = {name: 'xialei' }; const p = new Proxy(obj, {get(target, prop) {if(prop in target) {return target[prop].toUpperCase();}return undefined;} });console.log(p.name); // XIALEI

*handler.set(target, prop, value, receiver)

說明:屬性寫入訪問器
觸發時機:對代理對象的屬性進行賦值時觸發

參數:

target Object 目標對象
prop string|number|Symbol 屬性名
value any 屬性值
receiver Proxy 代理對象或原型鏈上的代理對象

返回值:

boolean 賦值成功返回true,否則返回false。嚴格模式下返回false會拋出TypeError

*handler.deleteProperty(target, prop)

說明:刪除對象屬性
觸發時機:對代理對象的屬性進行delete時觸發

參數:

target Object 目標對象
prop string|number|Symbol 屬性名

返回值:

boolean 刪除成功返回true,否則返回false。嚴格模式下返回false會拋出TypeError

*handler.apply(target, thisArg, args)

說明:攔截函數調用,被代理對象必須是函數
觸發時機:

直接調用函數 obj.xxx()或xxx()
apply/call

參數:

target Object 目標函數
thisArg Object this對象
args Array 參數列表

返回值:

any 任何值

function sum(a, b) {return a b; } const absSum = new Proxy(sum, {apply(target, thisArg, args) {const value = target.apply(thisArg, args);return value < 0 ? -value : value;} });console.log(absSum(-1, -2)); // 3,因為被攔截了

*handler.construct(target,args)

說明:攔截構造過程
觸發時機:new 目標構造函數(…args)

參數:

target Function 構造函數
args Array 構造函數的參數

返回值:

Object 對象

function Person(name) {this.name = name; }const P = new Proxy(Person, {construct(target, args, newTarget) {console.log(newTarget, newTarget === P, newTarget === Person); // [Function: Person] true falsereturn new target(args[0].toUpperCase());} });const p = new P('xialei');console.log(p); // Person { name: 'XIALEI' }

使用場景

保護目標對象(通過鉤子方法進行攔截)

數據轉換(上文有一個內存保護的例子)

數據驗證(不符合規則的值不允許設置)

const privateUser = {name: 'xialei',phone: '13888888888' };const user = new Proxy(privateUser, {set(target, prop, value) {if (prop === 'phone' && !/^(\ 86)?1[\d]{10}$/.test(value)) {return false;}target[prop] = value;return true;} });user.phone = '13666666666'; console.log(user.phone); // 13666666666 user.phone = ' 8613777777777'; console.log(user.phone); // 8613777777777 user.phone = '1'; console.log(user.phone); // 8613777777777

數據修正(也做數據標準化)

const privateUser = {name: 'xialei',phone: '13888888888' };const user = new Proxy(privateUser, {set(target, prop, value) {if (prop === 'phone' && !/^(\ 86)?1[\d]{10}$/.test(value)) {return false;}target[prop] = value.replace(' 86','');return true;} });user.phone = ' 8613666666666'; console.log(user.phone); // 13666666666

添加實用方法

const list = [{ name: 'xialei', phone: '13888888888' },{ name: 'xialei1', phone: '13899999999' }, ];const mList = new Proxy(list, {get(target, prop) {if (prop in target) {return target[prop];}for (const item of target) {if (item.name === prop) {return item;}}return undefined;} });const firstItem = mList[0]; const itemXialei = mList["xialei"];console.log(firstItem); // { name: 'xialei', phone: '13888888888' } console.log(itemXialei);// { name: 'xialei', phone: '13888888888' }

提供易用API

// 本例對localStorage做了封裝,可以像普通對象一樣操作localStorage,而不需要調用方法 const storage = new Proxy(localStorage, {get(target, prop) {return localStorage.getItem(prop);},set(target, prop, value) {localStorage.setItem(prop, value);return true;},deleteProperty(target, prop) {localStorage.removeItem(prop);},has(target, prop) {return localStorage.getItem(prop) !== null;} });storage.aaa = '1'; console.log(storage.aaa); // '1' delete storage.aaa; console.log(storage.aaa); // undefined

總結

Proxy的語法雖然簡單,但是可謂前途無量,比如開了一個Virtual Dom框架也是可以的。

更多原創文章,盡在每天進步一點點

總結

以上是生活随笔為你收集整理的深入浅出ES6的标准内置对象Proxy的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。