日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

JS帶你深入領(lǐng)略Proxy的世界

瀏覽:181日期:2024-03-26 08:48:50
目錄1. Proxy 的基本結(jié)構(gòu)2. Proxy 與 Reflect3. 代理數(shù)組4. 代理函數(shù)5. 一些簡(jiǎn)單的應(yīng)用場(chǎng)景5.1 統(tǒng)計(jì)函數(shù)被調(diào)用的上下文和次數(shù)5.2 實(shí)現(xiàn)一個(gè)防抖功能5.3 實(shí)現(xiàn)觀察者模式6. Proxy 與 Object.defineProperty 的對(duì)比6.1 Object.defineProperty 的優(yōu)劣6.2 Proxy 的優(yōu)劣7. 總結(jié)1. Proxy 的基本結(jié)構(gòu)

Proxy 的基本使用方式:

/** * target: 表示要代理的目標(biāo),可以是object, array, function類(lèi)型 * handler: 是一個(gè)對(duì)象,可以編寫(xiě)各種代理的方法 */const proxy = new Proxy(target, handler);

例如我們想要代理一個(gè)對(duì)象,可以通過(guò)設(shè)置 get 和 set 方法來(lái)代理獲取和設(shè)置數(shù)據(jù)的操作:

const person = { name: ’wenzi’, age: 20,};const personProxy = new Proxy(person, { get(target, key, receiver) { console.log(`get value by ${key}`); return target[key]; }, set(target, key, value) { console.log(`set ${key}, old value ${target[key]} to ${value}`); target[key] = value; },});

Proxy 僅僅是一個(gè)代理,personProxy 上有 person 所有的屬性和方法。我們通過(guò)personProxy獲取和設(shè)置 name 時(shí),就會(huì)有相應(yīng)的 log 輸出:

personProxy.name; // 'wenzi'// log: get value by namepersonProxy.name = ’hello’;// log: set name, old value wenzi to hello

并且通過(guò) personProxy 設(shè)置數(shù)據(jù)時(shí),代理的原結(jié)構(gòu)里的數(shù)據(jù)也會(huì)發(fā)生變化。我們打印下 person,可以發(fā)現(xiàn)字段 name 的值 也變成了hello:

console.log(person); // {name: 'hello', age: 20}

Proxy 的第 2 個(gè)參數(shù) handler 除了可以設(shè)置 get 和 set 方法外,還有更多豐富的方法:

1.get(target, propKey, receiver):攔截對(duì)象屬性的讀取,比如 proxy.foo 和 proxy[’foo’]。

2.set(target, propKey, value, receiver):攔截對(duì)象屬性的設(shè)置,比如 proxy.foo = v 或 proxy[’foo’] = v,返回一個(gè)布爾值。

3.has(target, propKey):攔截 propKey in proxy 的操作,返回一個(gè)布爾值。

4.deleteProperty(target, propKey):攔截 delete proxy[propKey]的操作,返回一個(gè)布爾值。

5.ownKeys(target):攔截 Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for...in 循環(huán),返回一個(gè)數(shù)組。該方法返回目標(biāo)對(duì)象所有自身的屬性的屬性名,而 Object.keys()的返回結(jié)果僅包括目標(biāo)對(duì)象自身的可遍歷屬性。

6.getOwnPropertyDescriptor(target, propKey):攔截 Object.getOwnPropertyDescriptor(proxy, propKey),返回屬性的描述對(duì)象。

7.defineProperty(target, propKey, propDesc):攔截 Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一個(gè)布爾值。

8.preventExtensions(target):攔截 Object.preventExtensions(proxy),返回一個(gè)布爾值。

9.getPrototypeOf(target):攔截 Object.getPrototypeOf(proxy),返回一個(gè)對(duì)象。

10.isExtensible(target):攔截 Object.isExtensible(proxy),返回一個(gè)布爾值。

11.setPrototypeOf(target, proto):攔截 Object.setPrototypeOf(proxy, proto),返回一個(gè)布爾值。如果目標(biāo)對(duì)象是函數(shù),那么還有兩種額外操作可以攔截。

12.apply(target, object, args):攔截 Proxy 實(shí)例作為函數(shù)調(diào)用的操作,比如 proxy(...args)、proxy.call(object, ...args)、proxy.apply(...)。

13.construct(target, args):攔截 Proxy 實(shí)例作為構(gòu)造函數(shù)調(diào)用的操作,比如 new proxy(...args)。

如我們通過(guò) delete 刪除其中一個(gè)元素時(shí),可以通過(guò)deleteProperty()方法來(lái)攔截這個(gè)操作。還是上面代理 person 的代碼,我們添加一個(gè) deleteProperty:

const person = { name: ’wenzi’, age: 20,};const personProxy = new Proxy(person, { // 忽略get和set方法,與上面一樣 // ... deleteProperty(target, key, receiver) { console.log(`delete key ${key}`); delete target[key]; },});

當(dāng)執(zhí)行 delete 操作時(shí):

delete personProxy[’age’];// log: delete key age2. Proxy 與 Reflect

Proxy 與 Reflect 可以說(shuō)形影不離了,Reflect 里所有的方法和使用方式與 Proxy 完全一樣。

例如上面 Proxy 里的 get(), set()和 deleteProperty()方法我們都是直接操作原代理對(duì)象的,這里我們改成使用Reflect來(lái)操作:

const personProxy = new Proxy(person, { get(target, key, receiver) { console.log(`get value by ${key}`); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { console.log(`set ${key}, old value ${target[key]} to ${value}`); return Reflect.set(target, key, value, receiver); }, deleteProperty(target, key, receiver) { console.log(`delete key ${key}`); return Reflect.deleteProperty(target, key, receiver); },});

可以發(fā)現(xiàn)完美地實(shí)現(xiàn)這些功能。

JS帶你深入領(lǐng)略Proxy的世界

3. 代理數(shù)組

我們?cè)谥暗奈恼?Vue 中對(duì)數(shù)組特殊的操作 中,討論過(guò) Vue 為什么沒(méi)有使用Object.defineProperty來(lái)劫持?jǐn)?shù)據(jù),而是重寫(xiě)了 Array 原型鏈上的幾個(gè)方法,通過(guò)這幾個(gè)方法來(lái)實(shí)現(xiàn) Vue 模板中數(shù)據(jù)的更新。

但若 Proxy 的話,就可以直接代理數(shù)組:

const arr = [1, 2, 3, 4];const arrProxy = new Proxy(arr, { get(target, key, receiver) { console.log(’arrProxy.get’, target, key); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { console.log(’arrProxy.set’, target, key, value); return Reflect.set(target, key, value, receiver); }, deleteProperty(target, key) { console.log(’arrProxy.deleteProperty’, target, key); return Reflect.deleteProperty(target, key); },});

現(xiàn)在我們?cè)賮?lái)操作一下代理后的數(shù)組 arrProxy 看下:

arrProxy[2] = 22; // arrProxy.set (4) [1, 2, 3, 4] 2 22arrProxy[3]; // arrProxy.get (4) [1, 2, 22, 4] 3delete arrProxy[2]; // arrProxy.deleteProperty (4) [1, 2, 22, 4] 2arrProxy.push(5); // push操作比較復(fù)雜,這里進(jìn)行了多個(gè)get()和set()操作arrProxy.length; // arrProxy.get (5) [1, 2, empty, 4, 5] length

可以看到無(wú)論獲取、刪除還是修改數(shù)據(jù),都可以感知到。還有數(shù)組原型鏈上的一些方法,如:

1.push()

2.pop()

3.shift()

4.unshift()

5.splice()

6.sort()

7.reverse()

也都能通過(guò) Proxy 中的代理方法劫持到。

concat()方法比較特殊的是,他是一個(gè)賦值操作,并不改變?cè)瓟?shù)組,因此在調(diào)用 concat()方法操作數(shù)組時(shí),如果沒(méi)有賦值操作,那么這里只有 get()攔截到。

JS帶你深入領(lǐng)略Proxy的世界

4. 代理函數(shù)

Proxy 中還有一個(gè)apply()方法,是表示自己作為函數(shù)調(diào)用時(shí),被攔截的操作。

const getSum = (...args) => { if (!args.every((item) => typeof item === ’number’)) { throw new TypeError(’參數(shù)應(yīng)當(dāng)均為number類(lèi)型’); } return args.reduce((sum, item) => sum + item, 0);};const fnProxy = new Proxy(getSum, { /** * @params {Fuction} target 代理的對(duì)象 * @params {any} ctx 執(zhí)行的上下文 * @params {any} args 參數(shù) */ apply(target, ctx, args) { console.log(’ctx’, ctx); console.log(`execute fn ${getSum.name}, args: ${args}`); return Reflect.apply(target, ctx, args); },});

執(zhí)行 fnProxy:

// 10, ctx為undefined, log: execute fn getSum, args: 1,2,3,4fnProxy(1, 2, 3, 4);// ctx為undefined, Uncaught TypeError: 參數(shù)應(yīng)當(dāng)均為number類(lèi)型fnProxy(1, 2, 3, ’4’);// 10, ctx為window, log: execute fn getSum, args: 1,2,3,4fnProxy.apply(window, [1, 2, 3, 4]);// 6, ctx為window, log: execute fn getSum, args: 1,2,3fnProxy.call(window, 1, 2, 3);// 6, ctx為person, log: execute fn getSum, args: 1,2,3fnProxy.apply(person, [1, 2, 3]);5. 一些簡(jiǎn)單的應(yīng)用場(chǎng)景

我們知道 Vue3 里已經(jīng)用 Proxy 重寫(xiě)了響應(yīng)式系統(tǒng),mobx 也已經(jīng)用了 Proxy 模式。在可見(jiàn)的未來(lái),會(huì)有更多的 Proxy 的應(yīng)用場(chǎng)景,我們這里也稍微講解幾個(gè)。

5.1 統(tǒng)計(jì)函數(shù)被調(diào)用的上下文和次數(shù)

這里我們用 Proxy 來(lái)代理函數(shù),然后函數(shù)被調(diào)用的上下文和次數(shù)。

const countExecute = (fn) => { let count = 0; return new Proxy(fn, { apply(target, ctx, args) { ++count; console.log(’ctx上下文:’, ctx); console.log(`${fn.name} 已被調(diào)用 ${count} 次`); return Reflect.apply(target, ctx, args); }, });};

現(xiàn)在我們來(lái)代理下剛才的getSum()方法:

const getSum = (...args) => { if (!args.every((item) => typeof item === ’number’)) { throw new TypeError(’參數(shù)應(yīng)當(dāng)均為number類(lèi)型’); } return args.reduce((sum, item) => sum + item, 0);};const useSum = countExecute(getSum);useSum(1, 2, 3); // getSum 已被調(diào)用 1 次useSum.apply(window, [2, 3, 4]); // getSum 已被調(diào)用 2 次useSum.call(person, 3, 4, 5); // getSum 已被調(diào)用 3 次5.2 實(shí)現(xiàn)一個(gè)防抖功能

基于上面統(tǒng)計(jì)函數(shù)調(diào)用次數(shù)的功能,也給我們實(shí)現(xiàn)一個(gè)函數(shù)的防抖功能添加了靈感。

const throttleByProxy = (fn, rate) => { let lastTime = 0; return new Proxy(fn, { apply(target, ctx, args) { const now = Date.now(); if (now - lastTime > rate) {lastTime = now;return Reflect.apply(target, ctx, args); } }, });};const logTimeStamp = () => console.log(Date.now());window.addEventListener(’scroll’, throttleByProxy(logTimeStamp, 300));

logTimeStamp()至少需要 300ms 才能執(zhí)行一次。

5.3 實(shí)現(xiàn)觀察者模式

我們?cè)谶@里實(shí)現(xiàn)一個(gè)最簡(jiǎn)單類(lèi) mobx 觀察者模式。

const list = new Set();const observe = (fn) => list.add(fn);const observable = (obj) => { return new Proxy(obj, { set(target, key, value, receiver) { const result = Reflect.set(target, key, value, receiver); list.forEach((observer) => observer()); return result; }, });};const person = observable({ name: ’wenzi’, age: 20 });const App = () => { console.log(`App -> name: ${person.name}, age: ${person.age}`);};observe(App);

person就是使用 Proxy 創(chuàng)建出來(lái)的代理對(duì)象,每當(dāng) person 中的屬性發(fā)生變化時(shí),就會(huì)執(zhí)行 App()函數(shù)。這樣就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的響應(yīng)式狀態(tài)管理。

6. Proxy 與 Object.defineProperty 的對(duì)比

上面很多例子用Object.defineProperty也都是可以實(shí)現(xiàn)的。那么這兩者都各有什么優(yōu)缺點(diǎn)呢?

6.1 Object.defineProperty 的優(yōu)劣

Object.defineProperty的兼容性可以說(shuō)比 Proxy 要好很多,出特別低的 IE6,IE7 瀏覽器外,其他瀏覽器都有支持。

但 Object.defineProperty 支持的方法很多,并且主要是基于屬性進(jìn)行攔截的。因此在 Vue2 中只能重寫(xiě) Array 原型鏈上的方法,來(lái)操作數(shù)組。

6.2 Proxy 的優(yōu)劣

Proxy與上面的正好相反,Proxy 是基于對(duì)象來(lái)進(jìn)行代理的,因此可代理更多的類(lèi)型,例如 Object, Array, Function 等;而且代理的方法也多了很多。

劣勢(shì)就是兼容性不太好,即使用 polyfill,也無(wú)法完美的實(shí)現(xiàn)。

7. 總結(jié)

Proxy 能實(shí)現(xiàn)的功能還有很多,后面我們也會(huì)繼續(xù)進(jìn)行探索,并且盡可能去了解下基于 Proxy 實(shí)現(xiàn)的類(lèi)庫(kù),例如 mobx5 的源碼和實(shí)現(xiàn)原理等。

以上就是JS帶你深入領(lǐng)略Proxy的世界的詳細(xì)內(nèi)容,更多關(guān)于JS中的代理Proxy的資料請(qǐng)關(guān)注好吧啦網(wǎng)其它相關(guān)文章!

標(biāo)簽: JavaScript
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产91久久精品一区二区| 性色一区二区| 日本在线不卡视频| 亚洲资源在线| 男人天堂欧美日韩| 欧美不卡视频| 亚洲一区日本| 日韩激情综合| 麻豆国产精品777777在线| 欧美黑人做爰爽爽爽| 国产成人精品三级高清久久91| 久久精品一区二区三区中文字幕| 国产va免费精品观看精品视频| 视频在线不卡免费观看| 亚洲精品在线影院| 免费久久99精品国产自在现线| 婷婷成人av| 福利视频一区| 午夜在线视频一区二区区别| 男女性色大片免费观看一区二区 | 久久久精品区| 久久蜜桃av| 日韩成人av影视| 精品国产麻豆| 国产精品毛片在线| 欧美一区成人| 亚洲91久久| 国产亚洲一区二区三区不卡| 国产精品黄色| 9色精品在线| 久久69成人| 首页亚洲欧美制服丝腿| 国产精品白丝av嫩草影院| 婷婷综合六月| 国产乱人伦精品一区| 91一区二区三区四区| 午夜亚洲福利在线老司机| 久久免费视频66| 日韩视频1区| 亚洲在线电影| 亚洲成av在线| 日韩精品视频网| 日韩一区二区免费看| 欧美一级二区| 免费观看在线综合| 激情欧美国产欧美| 日韩成人免费| 久久亚洲国产精品尤物| 亚洲91在线| 亚洲欧美激情诱惑| 伊人久久亚洲热| 亚洲免费一区二区| 国产亚洲综合精品| 狠狠爱成人网| 国产手机视频一区二区| 午夜电影亚洲| 黑丝一区二区三区| 男女男精品网站| 免费久久99精品国产自在现线| 黑丝美女一区二区| 秋霞影视一区二区三区| 99国产精品免费视频观看| 亚洲天堂av影院| 亚洲伊人av| 久久精品一区二区三区中文字幕| 国产精品香蕉| 欧美韩一区二区| 国产精品igao视频网网址不卡日韩| 青青草视频一区| 国产美女久久| 日本一区二区免费高清| 国产不卡av一区二区| 性欧美videohd高精| 国产精品99一区二区三区| 国产亚洲一区二区手机在线观看| 极品日韩av| 亚洲免费毛片| 国产精品久久久久久久久久白浆 | 久久久国产精品入口麻豆| 欧美www视频在线观看| 久久99久久人婷婷精品综合| 久久影院资源站| 韩国精品主播一区二区在线观看| 黄色日韩精品| 日本aⅴ精品一区二区三区| 欧美激情麻豆| 午夜影院欧美| 国产欧美高清视频在线| 高清一区二区| 91九色精品| 欧美日韩亚洲三区| 肉色欧美久久久久久久免费看| 亚洲一区二区成人| 精品美女视频| 久久国产66| 精品国产精品国产偷麻豆| 欧美日韩高清| 精品欧美视频| 日本欧美在线看| 欧美三级网址| 国产午夜一区| 久久夜色精品| 久久国产电影| 精品黄色一级片| 亚州国产精品| 精品91久久久久| 国产精品精品| 日韩免费精品| 在线视频亚洲| 热三久草你在线| 日韩综合一区二区| 久久国产亚洲| 国产在线视频欧美一区| 国产日韩欧美在线播放不卡| 蜜桃传媒麻豆第一区在线观看| 亚洲高清av| 福利一区和二区| 国产精品多人| 日日夜夜免费精品视频| 免费一区二区视频| 国产一区导航| 日韩精品一二三区| 蜜桃视频一区二区三区 | 精品三级国产| 久久久国产精品网站| 欧美日韩一视频区二区| 日本免费新一区视频| 四虎精品永久免费| 婷婷精品在线| 国产日韩三级| 国产精品探花在线观看| 91精品视频一区二区| 国产精品亚洲四区在线观看 | 久久国产小视频| 日韩精品dvd| 色天使综合视频| 免费黄色成人| 亚洲狼人精品一区二区三区| 午夜电影一区| 国产精品美女久久久久久不卡| 欧美国产日韩电影| 色婷婷色综合| 激情丁香综合| 日韩一区二区三区精品| 国产精品三级| 久久精品影视| 石原莉奈一区二区三区在线观看| 日本中文字幕不卡| 久久丁香四色| 国产字幕视频一区二区| 激情视频一区二区三区| 亚洲精品少妇| 精品国产美女a久久9999| 婷婷综合五月| 国产精品天堂蜜av在线播放| 国产h片在线观看| 免费看日韩精品| 日韩综合在线| 亚洲九九精品| 日韩久久视频| 日韩久久一区| 婷婷成人在线| 国产精品xvideos88| 成人av二区| 另类欧美日韩国产在线| 99久久99久久精品国产片果冰 | 久久精品1区| 国产精品一区二区三区美女| 国产在线日韩| 国产精品www.| 亚洲精选91| 国产一区亚洲| 久久久一本精品| 国产精品久一| 蜜桃视频一区二区| 欧美成人午夜| 国产一区不卡| 日韩国产高清在线| 在线亚洲一区| 国产色播av在线| 欧美国产另类| 欧美日韩中文| 日本综合视频| 日本亚洲三级在线| 蜜桃av一区二区| 中文一区一区三区免费在线观| 国产精品久久久久av电视剧| 国产精品videossex久久发布 | 麻豆极品一区二区三区| 日韩欧美另类中文字幕| 在线一区视频观看| 高清精品久久| 高清av一区| 欧美aa在线观看| 久久视频一区| 黄色不卡一区| 久久xxxx| 欧美日韩一区二区三区不卡视频| 国产精品sm| 色网在线免费观看|