學習 vue2.0/3.0 中的proxy和Object.defineProperty 小記


  vue3.0將雙向數據綁定的主要方法從Object.defineProperty舍棄,使用了proxy的方式通過觀察者模式實現相關的數據變化監聽,總的來說是一個很好地前進。今天簡單的實驗了一下相關的實現和不同情況下的使用輸出。簡單記錄一下吧。同時說明代碼中是使用數組的例子進行區分的。

  個人認為proxy的實現方式要比Object.defineProperty優雅很多,Object.defineProperty首先是指數據劫持,實際上proxy的運行是后置於Object.defineProperty,也就是說如果對同一個對象進行倆者同時使用的時候,要注意Object.defineProperty的各個參數是否會影響proxy內部的設置,例如configurable屬性如果設置了不可修改,那么在proxy進行代理時,在get方法中最終改變了輸出的內容,是會出現問題的。

   var data = {}
    Object.defineProperty(data, 'a', {
      value: 1,
      configurable: true,
    })
    let proxy = new Proxy(data, {
      get(obj, prop) {
        console.log('get');
        return 2;
      },
      set(obj, prop, val) {
        console.log('set');
        console.log(obj);
        obj[prop]= val;
        return true;
      }
    });
    console.log(proxy.a);

  如果此處的configurable不設置為true則會報錯。除此之外Object.defineProperty另外的兩個屬性也有一些自己的使用方法在其中。使用的時候要注意。

  同時由上面的代碼可以明顯的看出proxy的方式對對象進行設置代理的時候,會比Object.defineProperty進行劫持的時候方便很多,因為Object.defineProperty需要對具體的某個屬性進行設置,這就導致了我們需要遍歷所有的對象內部的內容,之后對每個都進行劫持才可以達到想要的效果,而proxy僅僅對對象整體進行監控就好了。

  除此之外proxy也增加了對於數組的監控。

var data = {
  dataarr: [1,2,3,4]
};
let proxy = new Proxy(data.dataarr, {
  get(obj, prop) {
    return obj[prop];
  },
  set(obj, prop, val) {
    console.log('set');
    obj[prop]= val;
    return true;
  }
});
proxy.push(1);
console.log(data.dataarr); 
// set
// [1, 2, 3, 4, 1]

  此時在上面代碼中,如果添加了對應的數組內容。proxy會提示數組發生了變化。同樣的,使用諸如proxy[1] = 7等等都可以觸發更改,而Object.defineProperty則不同,它並不能在修改數組內容時觸發相應的更改。

var data = {};
var watch;
Object.defineProperty(data, 'dataarr', {
  set(val) {
    console.log('set');
    watch = val;
    return true;
  },
  get() {
    console.log('get');
    return watch;
  }
})
data.dataarr = [1,2,3,4];
data.dataarr.push(3);
// set
// get

  我們可以看到實際上第一個set是由你設置data.dataarr = [1,2,3,4]; 觸發產生的。而push操作實際上僅僅是修改了data.dataarr的內容,並沒有觸發set。

  但是但是。proxy雖然很好用,但是它的性能其實很差。差到什么地步呢?假設我們按照如下代碼檢測。

var _obj = {};
var proxy = new Proxy(_obj, {
  set: (obj, prop, value) => { _obj[prop] = value; }
});

var defineProp = {};
Object.defineProperty(defineProp, 'prop', {
  configurable: false,
  set: v => defineProp._v = v
});

//  上述為建立不同的對象

obj.prop = 5;

proxy.prop = 5;

defineProp.prop = 5;

// 為賦值語句。

  如果我們按照這樣的邏輯進行賦值代碼,最終實現的監測數據是這樣的

vanilla x 74,288,023 ops/sec ±0.78% (86 runs sampled)
proxy x 3,625,152 ops/sec ±2.51% (86 runs sampled)
defineProperty x 74,815,513 ops/sec ±0.80% (85 runs sampled)
Fastest is defineProperty,vanilla

ps:ops/sec為每秒執行次數,數字越大越好。

  可以看到速度會比defineProperty的方式整整慢了一倍多,如果當然還有其他的情況下的檢測,如果有興趣可以看https://thecodebarbarian.com/thoughts-on-es6-proxies-performance,一位大佬寫的檢測。但是這就像前面這篇文章結尾說的那樣。實際上對於執行速度的慢並不能影響proxy的推行,就例如promise的執行效率實際上要比回調的方式慢好多,但是依舊無法阻擋它推行的腳步,而且據一些國內大佬的檢測數據來看,在較新版本下的node運行promise已經比以前的速度要快了很多,也就是說其實技術的優化始終可以達到。我們要的首先都是要好,只要性能不會太限制使用就好。人們一起推進的力量是偉大的。總會優化到我們欣喜的模樣。vue3.0或許是一個很好的契機。借助vue3.0的推行,proxy的未來相信會越來越好。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM