利用Object.freeze() 提升性能


利用Object.freeze() 提升性能

Object.freeze() 方法可以凍結一個對象。一個被凍結的對象再也不能被修改;凍結了一個對象則不能向這個對象添加新的屬性,不能刪除已有屬性,不能修改該對象已有屬性的可枚舉性、可配置性、可寫性,以及不能修改已有屬性的值。此外,凍結一個對象后該對象的原型也不能被修改。freeze() 返回和傳入的參數相同的對象。

凍結對象

    var obj = {
      prop: function() {},
      foo: 'bar'
    };

    // 新的屬性會被添加, 已存在的屬性可能
    // 會被修改或移除
    obj.foo = 'baz';
    obj.lumpy = 'woof';
    delete obj.prop;

    // 作為參數傳遞的對象與返回的對象都被凍結
    // 所以不必保存返回的對象(因為兩個對象全等)
    var o = Object.freeze(obj);

    o === obj; // true
    Object.isFrozen(obj); // === true

    // 現在任何改變都會失效
    obj.foo = 'quux'; // 靜默地不做任何事
    // 靜默地不添加此屬性
    obj.quaxxor = 'the friendly duck';

    console.log(obj) // { foo: "baz", lumpy: "woof" }
    console.log(o) // { foo: "baz", lumpy: "woof" }
    // 在嚴格模式,如此行為將拋出 TypeErrors
    function fail(){
      'use strict';
      obj.foo = 'sparky'; // Cannot assign to read only property 'foo' of object '#<Object>'
      delete obj.quaxxor; // 返回true,因為quaxxor屬性從來未被添加
      obj.sparky = 'arf'; // Cannot add property sparky, object is not extensible
    }

    fail();

    // 試圖通過 Object.defineProperty 更改屬性
    // 下面兩個語句都會拋出 Cannot define property ohai, object is not extensible.
    Object.defineProperty(obj, 'ohai', { value: 17 });
    Object.defineProperty(obj, 'foo', { value: 'eit' });

    // 也不能更改原型
    // 下面兩個語句都會拋出  #<Object> is not extensible.
    Object.setPrototypeOf(obj, { x: 20 })
    obj.__proto__ = { x: 20 }
    

凍結數據

let a = [0];
Object.freeze(a); // 現在數組不能被修改了.

a[0]=1; // 1
a.push(2); // Cannot add property 1, object is not extensible

console.log(a); // [0]

被凍結的對象是不可變的。但也不總是這樣。下例展示了凍結對象不是常量對象(淺凍結)。

var obj = {
  internal: {}
};

Object.freeze(obj);
obj1.internal.a = 'aValue';

console.log(obj1); // { internal: { a: 'aValue' } }

對於一個常量對象,整個引用圖(直接和間接引用其他對象)只能引用不可變的凍結對象。凍結的對象被認為是不可變的,因為整個對象中的整個對象狀態(對其他對象的值和引用)是固定的。注意,字符串,數字和布爾總是不可變的,而函數和數組是對象。

要使對象不可變,需要遞歸凍結每個類型為對象的屬性(深凍結)。當你知道對象在引用圖中不包含任何 環 (循環引用)時,將根據你的設計逐個使用該模式,否則將觸發無限循環。對 deepFreeze() 的增強將是具有接收路徑(例如Array)參數的內部函數,以便當對象進入不變時,可以遞歸地調用 deepFreeze() 。你仍然有凍結不應凍結的對象的風險,例如[window]

// 深凍結函數.
function deepFreeze(obj) {
  // 取回定義在obj上的屬性名
  var propNames = Object.getOwnPropertyNames(obj);
  // 在凍結自身之前凍結屬性
  propNames.forEach(function(name) {
    var prop = obj[name];
    // 如果prop是個對象,凍結它
    if (typeof prop == 'object' && prop !== null)
      deepFreeze(prop);
  });
  // 凍結自身(no-op if already frozen)
  return Object.freeze(obj);
}

obj2 = {
  internal: {}
};

deepFreeze(obj2);
obj2.internal.a = 'anotherValue';
obj2.internal.a; // undefined

對比 Object.seal()

Object.seal()密封的對象可以改變它們現有的屬性。使用Object.freeze() 凍結的對象中現有屬性是不可變的。

使用

參考vue的源碼,定義響應式的時候,如果freeze后的數據,不會加上settergetter

地址: https://github.com/vuejs/vue/blob/v2.5.17/src/core/observer/index.js?1535281657346#L134


免責聲明!

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



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