浅聊vue双向绑定原理Object.defineProperty-/-Proxy
什么是雙向綁定?
當數據模型data變化時,頁面視圖會得到響應更新
vue又是怎么做的?
vue其實現原理是對data的getter/setter方法進行攔截(Object.defineProperty或者Proxy),利用發布訂閱的設計模式,在getter方法中進行訂閱,在setter方法中發布通知,讓所有訂閱者完成響應。
說這些的時候我們在剛使用vue2.x的就會遇到過數據更新了啊,為何頁面不更新呢。這其實就是Object.defineProperty在作祟。
而在vue3還沒有發布時,很火的一個話題就是Vue3將使用Proxy 取代Vue2 版本的Object.defineProperty。那么Proxy對比Object.defineProperty有什么優勢。
Proxy對比Object.defineProperty
Proxy
- Proxy可以直接監聽對象而非屬性
- Proxy可以直接監聽數組的變化
- Proxy有多達13種攔截方法,不限于apply、ownKeys、deleteProperty、has等等是Object.defineProperty不具備的
- Proxy返回的是一個新對象,我們可以只操作新的對象達到目的,不需要像Object.defineProperty一樣遍歷每個屬性有一定的性能提升
- Proxy作為新標準將受到瀏覽器廠商重點持續的性能優化,也就是傳說中的新標準的性能紅利
- Proxy直接實現對象屬性的新增/刪除
Object.defineProperty
-
Object.defineProperty只能劫持對象的屬性,需要遍歷對象的每一個屬性,如果屬性值也是對象,就需要遞歸進行深度遍歷。
-
Object.defineProperty劫持的是對象的屬性,所以新增屬性時,需要重新遍歷對象, 對其新增屬性再次使用Object.defineProperty進行劫持。也就是Vue2.x中給數組和對象新增屬性時,需要使用$set才能保證新增的屬性也是響應式的, $set內部也是通過調用Object.defineProperty去處理的。
冷知識
Object.defineProperty無法監聽數組數據的變化,但是為什么數組在使用push pop等方法的時候可以觸發頁面更新呢,那是因為vue內部攔截了這些方法。比如數組在使用push pop等方法的時候為什么可以觸發頁面更新呢,那是因為vue內部攔截了這些方法。
// 重寫push等方法,然后再把原型指回原方法var ARRAY_METHOD = [ 'push', 'pop', 'shift', 'unshift', 'reverse', 'sort', 'splice' ];var array_methods = Object.create(Array.prototype);ARRAY_METHOD.forEach(method => {array_methods[method] = function () {// 攔截方法return Array.prototype[method].apply(this, arguments);}});回歸正題我們分別用代碼簡單的實現下Proxy對比Object.defineProperty如何實現綁定的
Object.defineProperty實現
// 這是將要被劫持的對象 const data = {name: '', }; // 遍歷對象,對其屬性值進行劫持 Object.keys(data).forEach(function(key) {console.log('1')Object.defineProperty(data, key, {enumerable: true,configurable: true,get: function(newVal) {return val},set: function(newVal) {// 當屬性值發生變化時我們可以進行額外操作console.log(`大家好,我是${newVal}我被劫持了`);val = newVal;},}); }); data.name = '111';Proxy實現
const target = {name: '控制' };const handler = {get: function(target, key) {console.log(`${key} 被讀取`);return target[key];},set: function(target, key, value) {console.log(`${key} 被設置為 ${value}`);target[key] = value;} };const testObj = new Proxy(target, handler);console.log(testObj.name); // name 被讀取 及輸出名字 控制 testObj.name = 1; // name 被設置為 1 輸出 1Proxy參數介紹
1.get(target, propKey, receiver)
該方法的含義是:用于攔截某個屬性的讀取操作。它有三個參數,如下解析:
- target: 目標對象。
- propKey: 目標對象的屬性。
- receiver: (可選),該參數為上下文this對象
2.set(target, propKey, value, receiver)
該方法是用來攔截某個屬性的賦值操作,它可以接受四個參數,參數解析分別如下:
- target: 目標對象。
- propKey: 目標對象的屬性名
- value: 屬性值
- receiver(可選): 一般情況下是Proxy實列
3.has(target, propKey)
該方法是判斷某個目標對象是否有該屬性名。接收二個參數,分別為目標對象和屬性名。返回的是一個布爾型。
- target: 目標對象。
- propKey: 目標對象的屬性名
4.construct(target, args, newTarget)
該方法是用來攔截new命令的,它接收三個參數,分別為 目標對象,構造函數的參數對象及創造實列的對象。
第三個參數是可選的。它的作用是攔截對象屬性。
- target: 目標對象。
- args: 構造函數的參數對象
- newTarget:創造實列的對象
5.apply(target, object, args)
該方法是攔截函數的調用的。該方法接收三個參數,分別是目標對象。目標對象上下文this對象 和 目標對象的數組;它和 Reflect.apply參數是一樣的
第三個參數是可選的。它的作用是攔截對象屬性。
- target: 目標對象。
- object: 目標對象上下文this對象
- args:目標對象的數組
寫在最后的話大家不要忘記,點贊,評論,收藏
總結
以上是生活随笔為你收集整理的浅聊vue双向绑定原理Object.defineProperty-/-Proxy的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 翻拍何时才能结束啊
- 下一篇: 【专题:毫米波】简介