proxy實(shí)現(xiàn)vue3數(shù)據(jù)雙向綁定原理
一、proxy對(duì)比Object.defineProperty的優(yōu)點(diǎn)
proxy的優(yōu)點(diǎn):
- Proxy 可以直接監(jiān)聽對(duì)象而非屬性;
- Proxy 可以直接監(jiān)聽數(shù)組的變化;
- Proxy 有多達(dá) 13 種攔截方法,不限于 apply、ownKeys、deleteProperty、has 等等是Object.defineProperty 不具備的;
- Proxy 返回的是一個(gè)新對(duì)象,我們可以只操作新的對(duì)象達(dá)到目的,而 Object.defineProperty 只能遍歷對(duì)象屬性直接修改;
- Proxy 作為新標(biāo)準(zhǔn)將受到瀏覽器廠商重點(diǎn)持續(xù)的性能優(yōu)化,也就是傳說中的新標(biāo)準(zhǔn)的性能紅利;
Object.defineProperty 的優(yōu)勢(shì):
兼容性好:支持 IE9,而 Proxy 的存在瀏覽器兼容性問題,而且無(wú)法用 polyfill 磨平,因此 Vue 的作者才聲明需要等到下個(gè)大版本( 3.0 )才能用 Proxy 重寫。
二、、proxy監(jiān)聽對(duì)象的簡(jiǎn)單實(shí)現(xiàn)
1.代理對(duì)象簡(jiǎn)單實(shí)現(xiàn)
```javascript let data = {};// 定義一個(gè)空對(duì)象 let proxy = new Proxy(data, {});// 創(chuàng)建一個(gè) Proxy , 將 data 作為目標(biāo)對(duì)象 // 修改Proxy 代理對(duì)象的name屬性 proxy.name = 'shelley'; console.log(proxy); console.log(data) // { name: 'shelley' } // { name: 'shelley' } ```
2.補(bǔ)充知識(shí) Reflect
Reflect
對(duì)象與Proxy對(duì)象一樣,也是 ES6 為了操作對(duì)象而提供的新 API
我們需要在 handler.set()
中 return 一個(gè) Reflect.set(…arguments
) 來進(jìn)行賦值給目標(biāo)對(duì)象。
- Reflect.set方法設(shè)置target對(duì)象的name屬性等于value。如果name屬性設(shè)置了賦值函數(shù),則賦值函數(shù)的this綁定receiver。
- Reflect.get方法查找并返回target對(duì)象的name屬性,如果沒有該屬性,則返回undefined。
3.proxy方法
handler.set()方法 屬性設(shè)置操作的捕捉器。
```javascript let data = { name: 'shelley', age: '27' }; let p = new Proxy(data, { set(target, prop, value) { // target = 目標(biāo)對(duì)象 // prop = 設(shè)置的屬性 // value = 修改后的值 console.log(target, prop, value); // { name: 'shelley', age: '27' } age 18 return Reflect.set(...arguments); } }) p.age = 18; console.log(data); // { name: 'shelley', age: 18 } ```
- handler.get() 屬性讀取操作的捕捉器。
```javascript let data = { name: 'shelley', age: 22 }; let p = new Proxy(data, { get(target, prop){ console.log(target, prop);//{ name: 'shelley', age: 22 } age return Reflect.get(...arguments); } }) console.log(p.age);//22 ```
Object.defineProperty監(jiān)聽對(duì)象的簡(jiǎn)單實(shí)現(xiàn)
```javascript var o = {};// 創(chuàng)建一個(gè)新對(duì)象 var bValue = 39;// 在對(duì)象中添加一個(gè)設(shè)置了存取描述符屬性的示例 Object.defineProperty(o, 'bValue', { // 這代碼不會(huì)設(shè)置 o 的屬性,只有訪問的時(shí)候才會(huì) get() { return bValue; }, set(newValue) { console.log('set==>', newValue); bValue = newValue; } }); console.log(o) // {} // 進(jìn)入訪問器代理的bValue屬性的get方法,返回,并設(shè)置o對(duì)象里的bValue的值為38 console.log(o.bValue); // 38 // 進(jìn)入訪問器代理的bValue屬性的set方法,設(shè)置bValue的新值, // 再進(jìn)入get返回,并設(shè)置o對(duì)象里的bValue的值為40 o.bValue = 40; console.log(o.bValue) // 40 ```
小結(jié):
- es6 proxy代理器對(duì)比
es5 Object.defineProperty
,功能更加強(qiáng)大,提供了方法超多,甚至可以代理方法 - 為什么vue3.0才使用es6的proxy,未在2.0就使用;因?yàn)閑s6在部分瀏覽器中并未兼容,如ie的低版本,所以在**大部分主流瀏覽器都兼容**的情況下,才使用
三、手寫vue3.0雙向綁定-es6 Proxy
1、什么是Proxy
- Proxy取其英文意思即“代理”。所謂代理,是你要取得某樣?xùn)|西或?qū)ζ溥M(jìn)行某些操作的中間媒介,而不是直接作用在這個(gè)對(duì)象上。
- Proxy可以理解成在目標(biāo)對(duì)象前架設(shè)一層攔截層,外界訪問該對(duì)象都必須先通過這層攔截,因此提供一種機(jī)制可以對(duì)外界的訪問進(jìn)行攔截或過濾。
2、vue.js中使用雙向綁定
```javascript <div id="app"> <h2>{{msg}}</h2> <input type="text" v-model="msg"/> </div> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script> let vm = new Vue({ el: '#app', data: { msg: 'shelley' }, }) </script> ```
四、Proxy對(duì)比Object.defineProperty
Vue2.0中的雙向綁定,使用Object.defineProperty()進(jìn)行雙向綁定
缺點(diǎn):
- 無(wú)法對(duì)數(shù)組進(jìn)行監(jiān)聽,采用的是對(duì)數(shù)組的方法進(jìn)行重寫(push, pop,shift,unshift等等)。對(duì)此進(jìn)行雙向綁定和數(shù)據(jù)監(jiān)聽的操作
- 效率差,這主要是因?yàn)閷?duì)多層數(shù)據(jù)進(jìn)行一次性的遞歸操作,如果數(shù)據(jù)很多或者是很深層次,這樣性能非常的差
- 因?yàn)榫窒扌?,無(wú)法對(duì)新加/刪除的數(shù)據(jù)進(jìn)行監(jiān)聽,所以使用在vue2.0中使用$set進(jìn)行手動(dòng)添加
- Object.definePorperty()遞歸遍歷所有對(duì)象的所有屬性,當(dāng)數(shù)據(jù)層級(jí)較深時(shí),會(huì)造成性能影響。
- Object.definePorperty()只能作用在對(duì)象上,不能作用在數(shù)組上。
- Object.definePorperty()只能監(jiān)聽定義時(shí)的屬性,不能監(jiān)聽新增屬性。
- 由于Object.definePorperty()不能作用于數(shù)組,vue2.0選擇通過重寫數(shù)組方法原型的方式對(duì)數(shù)組數(shù)據(jù)進(jìn)行監(jiān)聽,但是仍然無(wú)法監(jiān)聽數(shù)組索引的變化和長(zhǎng)度的變更
Vue3.0中雙向綁定,使用Proxy和Reflect進(jìn)行雙向綁定
優(yōu)點(diǎn):
- Proxy可以對(duì)數(shù)組和對(duì)象進(jìn)行攔截和監(jiān)聽
缺點(diǎn):
- Proxy會(huì)出發(fā)多次set/get響應(yīng)
解決辦法:
- ①使用類似于
debounce
的操作,對(duì)其進(jìn)行優(yōu)化,使其值響應(yīng)一次 - ②(vue3.0中的解決方式),判斷key是否是target的自身屬性,以及value是否和target[key]相等,可以避免多余的set/get操作
Proxy只能代理一層,無(wú)法深度監(jiān)聽
- ①使用深度遞歸,對(duì)每一層進(jìn)行監(jiān)聽。巧妙的使用的Reflect.get()會(huì)返回對(duì)象內(nèi)層結(jié)構(gòu)的特性(下一層),判斷下一層是否還是對(duì)象,并且使用深度遞歸操作。但是在性能上又很大的影響
- ②使用weakMap,使用兩個(gè)weakMap來保存原始數(shù)據(jù)和可響應(yīng)數(shù)據(jù)。訪問數(shù)據(jù)時(shí)會(huì)從保存的數(shù)據(jù)中查找,如果沒有再對(duì)其進(jìn)行Proxy操作。
到此這篇關(guān)于proxy實(shí)現(xiàn)vue3數(shù)據(jù)雙向綁定原理的文章就介紹到這了,更多相關(guān)proxy實(shí)現(xiàn)vue3數(shù)據(jù)雙向綁定 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue項(xiàng)目中接入websocket時(shí)需要ip端口動(dòng)態(tài)部署問題
這篇文章主要介紹了vue項(xiàng)目中接入websocket時(shí)需要ip端口動(dòng)態(tài)部署問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09詳解Vue路由開啟keep-alive時(shí)的注意點(diǎn)
這篇文章主要介紹了詳解Vue路由開啟keep-alive時(shí)的注意點(diǎn),非常具有實(shí)用價(jià)值,有興趣的朋友可以了解一下2017-06-06vue-quill-editor+plupload富文本編輯器實(shí)例詳解
這篇文章主要介紹了vue-quill-editor+plupload富文本編輯器實(shí)例詳解,需要的朋友可以參考下2018-10-10vue實(shí)現(xiàn)書本翻頁(yè)動(dòng)畫效果實(shí)例詳解
這篇文章主要介紹了vue簡(jiǎn)單實(shí)現(xiàn)書本翻頁(yè)效果,需要的朋友可以參考下2022-04-04Vue3?使用v-md-editor如何動(dòng)態(tài)上傳圖片的方法實(shí)現(xiàn)
本文主要介紹了Vue3?使用v-md-editor如何動(dòng)態(tài)上傳圖片,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-08-08Ant Design Upload 文件上傳功能的實(shí)現(xiàn)
這篇文章主要介紹了Ant Design Upload 文件上傳功能的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04