在 Vue 的文檔中介紹數據綁定和響應時,特地標註了對於通過 Object.freeze() 方法的對象沒法進行更新響應。所以,特地去查了 Object.freeze() 方法的具體含義。javascript
Object.freeze() 方法用於凍結對象,禁止對於該對象的屬性進行修改(因爲數組本質也是對象
,所以該方法能夠對數組使用)。在 Mozilla MDN 中是以下介紹的:html
能夠凍結一個對象。一個被凍結的對象不再能被修改;凍結了一個對象則不能向這個對象添加新的屬性,不能刪除已有屬性,不能修改該對象已有屬性的可枚舉性、可配置性、可寫性,以及不能修改已有屬性的值。此外,凍結一個對象後該對象的原型也不能被修改vue
該方法的返回值是其參數自己。java
須要注意的是如下兩點git
Object.freeze() 和 const 變量聲明不一樣,也不承擔 const 的功能。github
const和Object.freeze()徹底不一樣vuex
如下代碼是正確的:數組
常規用法瀏覽器
明顯看到,a 的 prop 屬性未被改變,即便從新賦值了。bash
"深凍結"
要徹底凍結具備嵌套屬性的對象,您能夠編寫本身的庫或使用已有的庫來凍結對象,如Deepfreeze或immutable-js
// 深凍結函數.
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);
}
複製代碼
其實就是個簡單的遞歸方法。可是涉及到一個很重要,可是在寫業務邏輯的時候不多用的知識點 Object.getOwnPropertyNames(obj)
。咱們都知道在 JS 的 Object 中存在原型鏈屬性,經過這個方法能夠獲取全部的非原型鏈屬性。
Object.freeze()
提高性能除了組件上的優化,咱們還能夠對vue的依賴改造入手。初始化時,vue會對data作getter、setter改造,在現代瀏覽器裏,這個過程實際上挺快的,但仍然有優化空間。
Object.freeze()
能夠凍結一個對象,凍結以後不能向這個對象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對象已有屬性的可枚舉性、可配置性、可寫性。該方法返回被凍結的對象。
當你把一個普通的 JavaScript 對象傳給 Vue 實例的 data
選項,Vue 將遍歷此對象全部的屬性,並使用 Object.defineProperty 把這些屬性所有轉爲 getter/setter,這些 getter/setter 對用戶來講是不可見的,可是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。
但 Vue 在遇到像 Object.freeze()
這樣被設置爲不可配置以後的對象屬性時,不會爲對象加上 setter getter 等數據劫持的方法。參考 Vue 源碼
Vue observer 源碼
在基於 Vue 的一個 big table benchmark 裏,能夠看到在渲染一個一個 1000 x 10 的表格的時候,開啓Object.freeze()
先後從新渲染的對比。
big table benchmark
開啓優化以前
開啓優化以後
在這個例子裏,使用了 Object.freeze()
比不使用快了 4 倍
Object.freeze()
的性能會更好不使用Object.freeze()
的CPU開銷
使用 Object.freeze()
的CPU開銷
對比能夠看出,使用了 Object.freeze()
以後,減小了 observer 的開銷。
Object.freeze()
應用場景因爲 Object.freeze()
會把對象凍結,因此比較適合展現類的場景,若是你的數據屬性須要改變,能夠從新替換成一個新的 Object.freeze()
的對象。
修改 React props React生成的對象是不能修改props的, 但實踐中遇到須要修改props的狀況. 若是直接修改, js代碼將報錯, 緣由是props對象被凍結了, 能夠用Object.isFrozen()來檢測, 其結果是true. 說明該對象的屬性是隻讀的.
那麼, 有方法將props對象解凍, 從而進行修改嗎?
事實上, 在javascript中, 對象凍結後, 沒有辦法再解凍, 只能經過克隆一個具備相同屬性的新對象, 經過修改新對象的屬性來達到目的.
能夠這樣:
ES6: Object.assign({}, frozenObject);
lodash: _.assign({}, frozenObject);
複製代碼
來看實際代碼:
function modifyProps(component) {
let condictioin = this.props.condictioin,
newComponent = Object.assign({}, component),
newProps = Object.assign({}, component.props)
if (condictioin) {
if (condictioin.add) newProps.add = true
if (condictioin.del) newProps.del = true
}
newComponent.props = newProps
return newComponent
}
複製代碼
鎖定對象的方法
no new properties or methods can be added to the project 對象不可擴展, 即不能夠新增屬性或方法, 但能夠修改/刪除
same as prevent extension, plus prevents existing properties and methods from being deleted 在上面的基礎上,對象屬性不可刪除, 但能夠修改
same as seal, plus prevent existing properties and methods from being modified 在上面的基礎上,對象全部屬性只讀, 不可修改
以上三個方法分別可用Object.isExtensible(), Object.isSealed(), Object.isFrozen()來檢測
當一個 Vue 實例被建立時,它向 Vue 的響應式系統中加入了其 data 對象中能找到的全部的屬性。當這些屬性的值發生改變時,視圖將會產生「響應」,即匹配更新爲新的值。可是若是使用 Object.freeze(),這會阻止修改現有的屬性,也意味着響應系統沒法再追蹤變化。
具體使用辦法舉例:
<template>
<div>
<p>freeze後會改變嗎
{{obj.foo}}
</p>
<!-- 兩個都不能修改??爲何?第二個理論上應該是能夠修改的-->
<button @click="change">點我確認</button>
</div>
</template>
<script>
var obj = {
foo: '不會變'
}
Object.freeze(obj)
export default {
name: 'index',
data () {
return {
obj: obj
}
},
methods: {
change () {
this.obj.foo = '改變'
}
}
}
</script>
複製代碼
運行後:
從報錯能夠看出只讀屬性foo不能進行修改,Object.freeze()凍結的是值,你仍然能夠將變量的引用替換掉,將上述代碼更改成:
<button @click="change">點我確認</button>
change () {
this.obj = {
foo: '會改變'
}
}
複製代碼
Object.freeze()是ES5新增的特性,能夠凍結一個對象,凍結指的是不能向這個對象添加新的屬性,不能修改其已有屬性的值,不能刪除已有屬性,以及不能修改該對象已有屬性的可枚舉性、可配置性、可寫性。防止對象被修改。 若是你有一個巨大的數組或Object,而且確信數據不會修改,使用Object.freeze()可讓性能大幅提高。
Object.freeze()是ES5新增的特性,能夠凍結一個對象,防止對象被修改。
vue 1.0.18+對其提供了支持,對於data或vuex裏使用freeze凍結了的對象,vue不會作getter和setter的轉換。
若是你有一個巨大的數組或Object,而且確信數據不會修改,使用Object.freeze()可讓性能大幅提高。在個人實際開發中,這種提高大約有5~10倍,倍數隨着數據量遞增。
而且,Object.freeze()凍結的是值,你仍然能夠將變量的引用替換掉。舉個例子:
<p v-for="item in list">{{ item.value }}</p>
複製代碼
new Vue({
data: {
// vue不會對list裏的object作getter、setter綁定
list: Object.freeze([
{ value: 1 },
{ value: 2 }
])
},
created () {
// 界面不會有響應
this.list[0].value = 100;
// 下面兩種作法,界面都會響應
this.list = [
{ value: 100 },
{ value: 200 }
];
this.list = Object.freeze([
{ value: 100 },
{ value: 200 }
]);
}
})
複製代碼
vue的文檔沒有寫上這個特性,但這是個很是實用的作法,對於純展現的大數據,均可以使用Object.freeze提高性能。