站長資訊網
        最全最豐富的資訊網站

        vue2&vue3數據響應式原理分析及手動實現(實例詳解)

        本篇文章給大家帶來了vue2&vue3數據響應式原理分析及手動實現的相關知識,數據響應式視圖跟數據是自動更新的,數據更新的時候視圖是自動的更新的追蹤數據的變化,希望對大家有幫助。

        vue2&vue3數據響應式原理分析及手動實現(實例詳解)

        數據響應式

        • 視圖跟數據是自動更新的,數據更新的時候視圖是自動的更新的
        • 追蹤數據的變化,在讀取數據或者設置數據的時候能夠做一些劫持的一些操作
        • vue2 使用defineProperty
        • vue3 改用Proxy

        使用defineProperty

        如何追蹤變化

        var obj = {}var age  Object.defineProperty(obj, 'age', {     get: function() {         consoel.log('get age ...')         return age    },     set: function(val) {         console.log('set age ...')         age = val    }})obj.age =100 //set age ...console.log(obj.age)//get age ...

        對象obj在取age屬性的時候會調用數據劫持的get方法
        在給age屬性賦值的時候會調用set方法

        那怎么使用Object.defineProperty實現一個數據響應式呢

        function defineReactive(data) {   if (!data || Object.prototype.toString.call(data) !== '[object Object]')     return;   for (let key in data) {     let val = data[key];     Object.defineProperty(data, key, {       enumerable: true, //可枚舉       configurable: true, //可配置       get: function() {         track(data, key);         return val;       },       set: function() {         trigger(val, key);       },     });     if (typeof val === "object") {       defineReactive(val);     }   }}function trigger(val, key) {   console.log("sue set", val, key);}function track(val, key) {   console.log("sue set", val, key);}const data = {   name:'better',   firends:['1','2']}defineReactive(data)console.log(data.name)console.log(data.firends[1])console.log(data.firends[0])console.log(Object.prototype.toString.call(data))

        這個函數defineReactve用來對Object.defineProperty進行封裝,從函數名可以看出,起作用就是定義一個響應式數據,封裝后只需要傳遞data,key和val就行
        每當從data中讀取key的時候觸發track函數,往data的key中設置數據時,set函數中的trigger函數觸發

        數組的響應式

        我們通過Array原型上的方法來改變數組的內容不會觸發getter和setter
        整理發現Array原型中可以改變數組自身內容的方法有7個,分別push pop shift unshift splice sort reverse
        vue2 改寫了這這7種方法
        實現方式:
        以Array.propertype為原型創建一個arrayMethods對象,再使用Object.setPropertypeOf(o, arryMethods)將o的__proto__指向arrayMethods

        vue2&vue3數據響應式原理分析及手動實現(實例詳解)

        如何收集依賴

        使用

        <template><p>{{name}}</p></template>

        該模板中使用數據 name, 我們要觀察數據, 當數據的屬性發生變化的時候, 可以通知哪些使用的地方,
        這就是我們要先收集依賴,即把用到數據name的地方收集起來,然后等數據變化的時候,把之前收集好的依賴循環觸發一遍,總結來說就是getter中收集依賴,在setter中觸發依賴

        使用proxy

        Proxy對象用于創建一個對象的代理, 從而實現基本操作的攔截和定義(如屬性查找、賦值、枚舉、函數掉用等)

        const p = new Proxy(target, handler)
        • target

        • 要使用 Proxy 包裝的目標對象(可以是任何類型的對象,包括原生數組,函數,甚至另一個代理)。

        • handler

        • 一個通常以函數作為屬性的對象,各屬性中的函數分別定義了在執行各種操作時代理 p 的行為。
          reflect是一個內置對象, 他提供攔截javascript操作的方法, 這些方法和Proxy handlers相同

        Reflect.set將值分配給屬性的函數。返回一個Boolean 如果更新成功則返回true

        Reflect.get獲取對象身上某個屬性的值,類似target[name]

        如何實現劫持

        const dinner = {   meal:'111'}const handler = {   get(target, prop) {     console.log('get...', prop)     return Reflect.get(...arguments)   },   set(target, key, value) {     console.log('get...', prop)     console.log('set',key,value)     return Reflect.set(...arguments)   }}const proxy = new Proxy(dinner, handler)console.log(proxy.meal)console.log(proxy.meal)

        代碼中dinner 對象代理到handler上
        defineProperty區別
        defineProperty的屬性需要遍歷才能監管所有屬性

        使用proxy可以將對象所有屬性進行代理

        用proxy實現一個模擬響應式

        function reactive(obj) {   const handler = {     get(target, prop, receiver) {       track(target, prop);       const value =  Reflect.get(...arguments);       if(typeof value === 'Object') {         reactive(value)       }else {         return value      }     },     set(target,key, value, receiver) {       trigger(target,key, value);       return Reflect.set(...arguments);     },   };   return new Proxy(obj,handler)}function track(data, key) {   console.log("sue set", data, key);}function trigger(data, key,value) {   console.log("sue set", key,':',value);}const dinner = {   name:'haochi1'}const proxy  =reactive(dinner)proxy.name proxy.list = []proxy.list.push(1)

        執行后自動打印

        vue2&amp;vue3數據響應式原理分析及手動實現(實例詳解)

        思考:為啥只在get中使用遞歸,set不使用呢?

        賦值也需要先get

        簡單總結:

        1. vue2 (淺響應式)
        • 遍歷data,使用defineProperty攔截所有屬性
        • 當用戶操作視圖,會觸發set攔截器
        • set先改變當前數據, 再通知wartch, 讓watch去通知視圖更新
        • 視圖重繪, 再次從get中獲取對應的數據
        1. vue3 (深度響應式) :
        • 使用proxy 進行代理;攔截data任意屬性的任意操作(13種), 包括屬性的讀寫, 屬性的添加, 屬性的刪除等等

        • 使用Reflect進行反射; 動態對被代理的對象的相應屬性進行特定的操作

        • 代理對象(proxy)的反射對象(reflect)必須相互配合才能實現響應式

        兩者的不同

        Proxy能劫持整個對象,而Object.defineProperty只能劫持對象的屬性; 前者遞歸返回屬性對應的值的代理即可實現響應式,后者需要深度遍歷每個屬性,后者對數組的操作很不友好.

        贊(0)
        分享到: 更多 (0)
        網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
        主站蜘蛛池模板: 精品无码日韩一区二区三区不卡 | 国产乱人伦偷精品视频不卡| 亚洲精品国产首次亮相| 中文字幕精品视频| 99精品一区二区三区无码吞精| 亚洲国产精品ⅴa在线观看| 国产精品成人观看视频| 国产精品久久影院| 国产亚洲精品美女久久久 | 欧美精品久久久久久久自慰 | 无码人妻精品一区二区三区久久| 久99久无码精品视频免费播放| 日韩精品免费视频| 国产精品亚洲专区在线观看| 国产99视频精品免费专区| 无码国产精品一区二区免费式芒果| 久久免费国产精品| 精品国产午夜肉伦伦影院| 99熟女精品视频一区二区三区 | 国产精品自在线拍国产| 久久精品国产清高在天天线| 午夜精品射精入后重之免费观看 | 国产精品一区在线观看你懂的| 久久精品成人国产午夜| 国产成人精品日本亚洲直接| 国产精品久久久久久久久| 99精品在线观看| 国产精品视频久久久| 国产成人精品免费视频动漫| 91久久婷婷国产综合精品青草| 久久99精品久久久久久久不卡| 日韩国产成人精品视频| 伊人久久精品无码二区麻豆| 中文字幕av日韩精品一区二区| 亚洲精品美女久久久久99| 中文字幕精品久久久久人妻| 日韩精品无码AV成人观看| 国精品午夜福利视频不卡麻豆| jizz国产精品网站| 国产一精品一av一免费爽爽| 欧美国产亚洲精品高清不卡|