1. 程式人生 > 程式設計 >Vue3使用Proxy實現資料監聽的原因分析

Vue3使用Proxy實現資料監聽的原因分析

資料雙向繫結原理,而這個方法有缺點,並且不能實現陣列和物件的部分監聽情況;具體也可以看我之前寫的一篇部落格: 關於 Vue 不能 watch 陣列 和 物件變化的解決方案,最新的 Proxy,相比 vue2 的 Object.defineProperty,能達到速度加倍、記憶體減半的成效。具體是怎麼實現、以及對比舊的實現方法為啥能有速度加倍、記憶體減半的特性,下面我們來聊聊:

Vue 初始化過程

Vue 的初始化過程,分別有Observer、Compiler和Watcher,當我們 new Vue 的時候,會呼叫Observer,通過 Object.defineProperty 遍歷 vue 物件的 data、computed 或者 props(如果是元件的話)的所有屬性進行監聽。同時通過ComptfZDb

iler解析模板指令,解析到屬性後就 new 一個Watcher並繫結更新函式到 watcher 當中,Observer 和 Compiler 就通過屬性來進行關聯。

Object.defineProperty

來個簡單的 Object.defineProperty例子

class Observer {
    constructor(data) {
      // 遍歷引數 data 的屬性,給新增到 this 上
      for (let key of Object.keys(data)) {
        if (typeof data[key] === "object") {
          data[key] = new Observer(data[key]);
        }
        Object.defineProperty(this,key,{
          enumerable: true,configurable: true,get() {
            console.log("你訪問了" + key);//你訪問了age
            return data[key];//20
          },set(newVal) {
            console.log("你設定了" + key); //你設定了age
            console.log("新的" + key + "=" + newVal); //新的age=20
            if (newVal === data[key]) {
              return;
            }
            data[key] = newVal;
          }
        });
      }
    }
  }const obj = {
    name: "app",age: "18",a: {
      b: 1,c: 2,}
  };const app = new Observer(obj);app.age = 20;console.log(app.age);app.newPropKey = "新屬性";console.log(app.newPropKey);    //新屬性

從上面可以知道:Object.defineProperty 需要遍歷所有的屬性,這http://www.cppcns.com就造成了如果 vue 物件的data/computed/props 中的資料規模龐大,那麼遍歷起來就會慢很多.同理,如果 vue 物件的 data/computed/props 中的資料規模龐大,那麼 Object.defineProperty 需要監聽所有的屬性的變化,那麼佔用記憶體就會很大。

Proxy

我們來看看proxy

Proxy 物件用於定義基本操作的自定義行為(如屬性查詢,賦值,列舉,函式呼叫等)

可以理解為在物件之前設定一個”攔截“,當監聽的物件被訪問的時候,都必須經過這層攔截。可以在這攔截中對原物件處理,返回需要的資料格式,也就是無論訪問物件的什麼屬性,之前定義的或是新增的屬性,都會走到攔截中進行處理。這就解決了之前所無法監聽的問題。

const obj = {
  name: "krry",age: 24,others: {
    mobile: "mi10",watch: "mi4",},};const p = new Proxy(obj,{
  get(target,receiver) {
    console.log("檢視的屬性為:" + key);  
    return Reflect.get(target,receiver);
  },set(target,value,receiver) {
    console.log("設定的屬性為:" + key); 
    console.log("新的屬性:" + key,"值為:" + value); 
    Reflect.set(target,});p.age = 22;console.log(p.age); p.single = "NO";console.log(p.single);p.others.shoe = "boost";console.log(p.others.shoe);輸出結果為:設定的屬性為:age
新的屬性:age 值為:22檢視的屬性為:age22

設定的屬性為:single
新的屬性:single 值為:NO檢視的屬性為:singleNO 檢視的屬性為:others
檢視的屬性為:others
boost

由上可知,新增或編輯屬性,並不需要重新新增響應式處理,都能監聽的到,因為 Proxy 是對物件的操作,只要你訪問物件,就會走到 Proxy 的邏輯中。Reflect 是一個內建的物件,它提供攔截 操作的方法。這www.cppcns.com些方法與proxy handlers的方法相同。Reflect不是一個函式物件,因此它是不可構造的,區別Proxy 和 Object.defineProperty 的使用方法看似很相似,其實 Proxy 是在更高維度上去攔截屬性的。

Object.definePropertyVue2 中,對於給定的 data:如 { count: 1 },是需要根據具體的 key 也就是 count,去對 get 和 set 進行攔截,也就是:

Object.defineProperty(data,'count',{
  get() {},set() {},})

必須預先知道要攔截的 key 是什麼,這也就是為什麼 Vue2 裡對於物件上的新增屬性無能為力,所以 Vue 初始化的過程中需要遍歷 data 來挾持資料變化,造成速度變慢,記憶體變大的原因。

Proxy 而 Vue3 所使用的 Proxy,則是這樣攔截的:

new Proxy(data,{
  get(key) { },set(key,value) { },})

可以看到,proxy 不需要關心具體的 key,它去攔截的是修改 data 上的任意 key和讀取 data 上的任意 key

所以,不管是已有的 key 還是新增的 key,都會監聽到。

到此這篇關於Vue3使用Proxy實現資料監聽的原因分析的文章就介紹到這了,更多相關Vue3為什麼使用Proxy實現資料監聽內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!