利用Object.freeze() 提升效能
阿新 • • 發佈:2020-07-09
利用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
後的資料,不會加上setter
和getter
地址: https://github.com/vuejs/vue/blob/v2.5.17/src/core/observer/index.js?1535281657346#L134