亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > JS > 正文

JavaScript的Proxy可以做哪些有意思的事兒

2024-05-06 16:52:13
字體:
來源:轉載
供稿:網友

Proxy是什么

首先,我們要清楚,Proxy是什么意思,這個單詞翻譯過來,就是 代理。

可以理解為,有一個很火的明星,開通了一個微博賬號,這個賬號非常活躍,回復粉絲、到處點贊之類的,但可能并不是真的由本人在維護的。

而是在背后有一個其他人 or 團隊來運營,我們就可以稱他們為代理人,因為他們發表的微博就代表了明星本人的意思。

P.S. 強行舉例子,因為本人不追星,只是猜測可能會有這樣的運營團隊

這個代入到JavaScript當中來,就可以理解為對對象或者函數的代理操作。

JavaScript中的Proxy

Proxy是ES6中提供的新的API,可以用來定義對象各種基本操作的自定義行為 (在文檔中被稱為traps,我覺得可以理解為一個針對對象各種行為的鉤子),拿它可以做很多有意思的事情,在我們需要對一些對象的行為進行控制時將變得非常有效。

Proxy的語法

創建一個Proxy的實例需要傳入兩個參數

1.target 要被代理的對象,可以是一個object或者function

2.handlers對該代理對象的各種操作行為處理

let target = {}let handlers = {} // do nothinglet proxy = new Proxy(target, handlers)proxy.a = 123console.log(target.a) // 123

在第二個參數為空對象的情況下,基本可以理解為是對第一個參數做的一次淺拷貝
(Proxy必須是淺拷貝,如果是深拷貝則會失去了代理的意義)

Traps(各種行為的代理)

就像上邊的示例代碼一樣,如果沒有定義對應的trap,則不會起任何作用,相當于直接操作了target。

當我們寫了某個trap以后,在做對應的動作時,就會觸發我們的回調函數,由我們來控制被代理對象的行為。

最常用的兩個trap應該就是get和set了。

早年JavaScript有著在定義對象時針對某個屬性進行設置getter、setter:

let obj = {_age: 18,get age () {return `I'm ${this._age} years old`},set age (val) {this._age = Number(val)}}console.log(obj.age) // I'm 18 years oldobj.age = 19console.log(obj.age) // I'm 19 years old

就像這段代碼描述的一樣,我們設置了一個屬性_age,然后又設置了一個get age和set age。

然后我們可以直接調用obj.age來獲取一個返回值,也可以對其進行賦值。

這么做有幾個缺點:

1.針對每一個要代理的屬性都要編寫對應的getter、setter。

2.必須還要存在一個存儲真實值的key(如果我們直接在getter里邊調用this.age則會出現堆棧溢出的情況,因為無論何時調用this.age進行取值都會觸發getter)。

Proxy很好的解決了這兩個問題:

let target = { age: 18, name: 'Niko Bellic' }let handlers = {get (target, property) {return `${property}: ${target[property]}`},set (target, property, value) {target[property] = value}}let proxy = new Proxy(target, handlers)proxy.age = 19console.log(target.age, proxy.age) // 19, age : 19console.log(target.name, proxy.name) // Niko Bellic, name: Niko Bellic

我們通過創建get、set兩個trap來統一管理所有的操作,可以看到,在修改proxy的同時,target的內容也被修改,而且我們對proxy的行為進行了一些特殊的處理。

而且我們無需額外的用一個key來存儲真實的值,因為我們在trap內部操作的是target對象,而不是proxy對象。

拿Proxy來做些什么

因為在使用了Proxy后,對象的行為基本上都是可控的,所以我們能拿來做一些之前實現起來比較復雜的事情。

在下邊列出了幾個簡單的適用場景。

解決對象屬性為undefined的問題

在一些層級比較深的對象屬性獲取中,如何處理undefined一直是一個痛苦的過程,如果我們用Proxy可以很好的兼容這種情況。

(() => {let target = {}let handlers = {get: (target, property) => {target[property] = (property in target) ? target[property] : {}if (typeof target[property] === 'object') {return new Proxy(target[property], handlers)}return target[property]}}let proxy = new Proxy(target, handlers)console.log('z' in proxy.x.y) // false (其實這一步已經針對`target`創建了一個x.y的屬性)proxy.x.y.z = 'hello'console.log('z' in proxy.x.y) // trueconsole.log(target.x.y.z) // hello})()

我們代理了get,并在里邊進行邏輯處理,如果我們要進行get的值來自一個不存在的key,則我們會在target中創建對應個這個key,然后返回一個針對這個key的代理對象。

這樣就能夠保證我們的取值操作一定不會拋出can not get xxx from undefined
但是這會有一個小缺點,就是如果你確實要判斷這個key是否存在只能夠通過in操作符來判斷,而不能夠直接通過get來判斷。

普通函數與構造函數的兼容處理

如果我們提供了一個Class對象給其他人,或者說一個ES5版本的構造函數。
如果沒有使用new關鍵字來調用的話,Class對象會直接拋出異常,而ES5中的構造函數this指向則會變為調用函數時的作用域。
我們可以使用apply這個trap來兼容這種情況:

class Test {constructor (a, b) {console.log('constructor', a, b)}}// Test(1, 2) // throw an errorlet proxyClass = new Proxy(Test, {apply (target, thisArg, argumentsList) {// 如果想要禁止使用非new的方式來調用函數,直接拋出異常即可// throw new Error(`Function ${target.name} cannot be invoked without 'new'`)return new (target.bind(thisArg, ...argumentsList))()}})proxyClass(1, 2) // constructor 1 2

我們使用了apply來代理一些行為,在函數調用時會被觸發,因為我們明確的知道,代理的是一個Class或構造函數,所以我們直接在apply中使用new關鍵字來調用被代理的函數。

以及如果我們想要對函數進行限制,禁止使用new關鍵字來調用,可以用另一個trap:construct

function add (a, b) {return a + b}let proxy = new Proxy(add, {construct (target, argumentsList, newTarget) {throw new Error(`Function ${target.name} cannot be invoked with 'new'`)}})proxy(1, 2) // 3new proxy(1, 2) // throw an error

用Proxy來包裝fetch

在前端發送請求,我們現在經常用到的應該就是fetch了,一個原生提供的API。
我們可以用Proxy來包裝它,使其變得更易用。

let handlers = {get (target, property) {if (!target.init) {// 初始化對象['GET', 'POST'].forEach(method => {target[method] = (url, params = {}) => {return fetch(url, {headers: {'content-type': 'application/json'},mode: 'cors',credentials: 'same-origin',method,...params}).then(response => response.json())}})}return target[property]}}let API = new Proxy({}, handlers)await API.GET('XXX')await API.POST('XXX', {body: JSON.stringify({name: 1})})

對GET、POST進行了一層封裝,可以直接通過.GET這種方式來調用,并設置一些通用的參數。

實現一個簡易的斷言工具

寫過測試的各位童鞋,應該都會知道斷言這個東西
console.assert就是一個斷言工具,接受兩個參數,如果第一個為false,則會將第二個參數作為Error message拋出。
我們可以使用Proxy來做一個直接賦值就能實現斷言的工具。

let assert = new Proxy({}, {set (target, message, value) {if (!value) console.error(message)}})assert['Isn/'t true'] = false // Error: Isn't trueassert['Less than 18'] = 18 >= 19 // Error: Less than 18


統計函數調用次數
在做服務端時,我們可以用Proxy代理一些函數,來統計一段時間內調用的次數。
在后期做性能分析時可能會能夠用上:

function orginFunction () {}let proxyFunction = new Proxy(orginFunction, {apply (target, thisArg. argumentsList) {log(XXX)return target.apply(thisArg, argumentsList)}})

全部的traps

這里列出了handlers所有可以定義的行為 (traps):

具體的可以查看MDN-Proxy

里邊同樣有一些例子

 

traps description
get 獲取某個key值
set 設置某個key值
has 使用in操作符判斷某個key是否存在
apply 函數調用,僅在代理對象為function時有效
ownKeys 獲取目標對象所有的key
construct 函數通過實例化調用,僅在代理對象為function時有效
isExtensible 判斷對象是否可擴展,Object.isExtensible的代理
deleteProperty 刪除一個property
defineProperty 定義一個新的property
getPrototypeOf 獲取原型對象
setPrototypeOf 設置原型對象
preventExtensions 設置對象為不可擴展
getOwnPropertyDescriptor 獲取一個自有屬性 (不會去原型鏈查找) 的屬性描述

 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JavaScript/Ajax教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
热re91久久精品国99热蜜臀| 日韩精品中文在线观看| 国产精品精品久久久| 亚洲精品中文字幕有码专区| 日韩激情av在线免费观看| 69视频在线免费观看| 亚洲欧洲一区二区三区在线观看| 久久青草精品视频免费观看| 国产亚洲欧美一区| 国产精品91久久久久久| 欧美午夜宅男影院在线观看| 国内精品小视频| 亚洲国产成人一区| 2019中文字幕在线观看| 国产精品网站视频| 亚洲自拍另类欧美丝袜| 激情av一区二区| 亚洲精品在线91| 亚洲国产高清高潮精品美女| 最新69国产成人精品视频免费| 欧美自拍大量在线观看| 亚洲人成网在线播放| 久久夜色精品国产亚洲aⅴ| 日韩av网站电影| 日韩欧美中文字幕在线观看| 久久久久久久久久久亚洲| 精品视频偷偷看在线观看| www.日韩免费| 九九精品在线播放| 91国自产精品中文字幕亚洲| 成人精品福利视频| 亚洲专区中文字幕| 精品久久香蕉国产线看观看亚洲| 亚洲伦理中文字幕| 色婷婷综合成人| 亚洲成人网在线| 亚洲免费福利视频| 国产精品一久久香蕉国产线看观看| 91亚洲精品在线观看| 中文字幕精品视频| 国精产品一区一区三区有限在线| 国产精品视频最多的网站| 国产精品视频白浆免费视频| 日韩中文字幕欧美| 日韩小视频在线观看| 欧美高清视频一区二区| 欧美精品电影免费在线观看| 欧美大人香蕉在线| 国模gogo一区二区大胆私拍| 国产精品网站大全| 日韩美女视频中文字幕| 欧美日韩午夜视频在线观看| 日本a级片电影一区二区| 欧美激情一区二区三区久久久| 国产在线精品成人一区二区三区| 午夜精品久久久久久久男人的天堂| 中文字幕欧美日韩| 欧美电影免费观看电视剧大全| 久久最新资源网| 国产精品久久久久av| 欧美大片免费观看在线观看网站推荐| 欧美老妇交乱视频| 亚洲精品久久久久国产| 成人免费黄色网| 亚洲成人动漫在线播放| 国内精品久久久久久影视8| 欧美第一淫aaasss性| 国产精品久久久精品| 久久久久久久亚洲精品| 91sa在线看| 福利一区福利二区微拍刺激| 亚洲人成电影在线| 国内精品国产三级国产在线专| 亚洲视频视频在线| 国产视频福利一区| 黑人与娇小精品av专区| www.欧美视频| 在线中文字幕日韩| 国产亚洲欧洲黄色| 日韩av在线免费看| 亚洲精品中文字幕有码专区| 国产欧美精品xxxx另类| 岛国av在线不卡| 78色国产精品| 亚洲男人的天堂在线| 亚洲国产成人爱av在线播放| 欧美极度另类性三渗透| 欧美性少妇18aaaa视频| 中文字幕在线成人| 国产xxx69麻豆国语对白| 精品亚洲国产成av人片传媒| 久久色精品视频| 精品女厕一区二区三区| 日韩av手机在线看| 国产一区二区三区在线看| 久久精品国产一区| 91在线视频精品| 亚洲小视频在线| 亚洲成色www8888| 91精品在线看| 国产精品丝袜一区二区三区| 久久综合伊人77777蜜臀| 欧美日韩在线视频一区二区| 在线免费观看羞羞视频一区二区| 欧美丰满少妇xxxxx| 国产精品揄拍一区二区| 精品国产网站地址| 在线中文字幕日韩| 亚洲a级在线播放观看| 97色伦亚洲国产| 欧美资源在线观看| 欧美视频免费在线| 亚洲女人天堂av| 欧美成人三级视频网站| 日韩中文字幕国产精品| 一区二区三区 在线观看视| 亚洲精品99久久久久| 久久久久日韩精品久久久男男| 欧美成年人视频| 欧美成年人视频| 91精品啪aⅴ在线观看国产| 91爱视频在线| 一本色道久久综合亚洲精品小说| 久久精品国产一区二区三区| 色悠久久久久综合先锋影音下载| 国产精品日韩在线观看| 亚洲免费伊人电影在线观看av| 亚洲最大福利网站| 日韩中文字幕在线精品| 国产亚洲精品久久久久动| 亚洲男子天堂网| 一区二区三区四区在线观看视频| 亚洲一区二区少妇| 国产中文欧美精品| 精品国产电影一区| 日av在线播放中文不卡| 国产精品精品视频一区二区三区| 永久555www成人免费| 亚洲精品视频网上网址在线观看| 国产精品视频资源| 麻豆一区二区在线观看| 国产视频精品xxxx| 成人在线中文字幕| 中文字幕精品一区久久久久| 日本精品性网站在线观看| 狠狠色香婷婷久久亚洲精品| 欧美日韩亚洲一区二区| 91网站在线免费观看| 美女视频久久黄| 777国产偷窥盗摄精品视频| 欧美成人久久久| 最新69国产成人精品视频免费| 日韩视频免费观看| 91久久国产综合久久91精品网站| 日本人成精品视频在线| 欧美精品在线观看91| 中文字幕精品国产| 日韩黄色在线免费观看| 欧美国产视频日韩| 欧美视频在线观看 亚洲欧| 国产精品视频一区国模私拍| 成人h猎奇视频网站| 中文字幕国产日韩| 亚洲免费高清视频|