在 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提高性能。