在vue中,数据冻结“Object.freeze()”方法用于冻结对象,禁止对于该对象的属性进行修改(由于数组本质也是对象,因此该方法可以对数组使用)。对象冻结后,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值;此外,冻结一个对象后该对象的原型也不能被修改。

本教程操作环境:windows7系统、vue3版,DELL G3电脑。
在 Vue 的文档中介绍数据绑定和响应时,特意标注了对于经过 Object.freeze() 方法的对象无法进行更新响应。因此,特意去查了 Object.freeze() 方法的具体含义。
含义
Object.freeze() 方法用于冻结对象,禁止对于该对象的属性进行修改(由于数组本质也是对象,因此该方法可以对数组使用)。在 Mozilla MDN 中是如下介绍的:
可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,
不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。此外,冻结一个对象后该对象的原型也不能被修改
该方法的返回值是其参数本身。
需要注意的是以下两点
1、Object.freeze() 和 const 变量声明不同,也不承担 const 的功能。
const和Object.freeze()完全不同
- const的行为像 let。它们唯一的区别是, const定义了一个无法重新分配的变量。 通过 const声明的变量是具有块级作用域的,而不是像 var声明的变量具有函数作用域。
- Object.freeze()接受一个对象作为参数,并返回一个相同的不可变的对象。这就意味着我们不能添加,删除或更改对象的任何属性。
- const和Object.freeze()并不同,const是防止变量重新分配,而Object.freeze()是使对象具有不可变性。
以下代码是正确的:

2、Object.freeze() 是“浅冻结”,以下代码是生效的:

实例
常规用法

明显看到,a 的 prop 属性未被改变,即使重新赋值了。
延伸
"深冻结"
要完全冻结具有嵌套属性的对象,您可以编写自己的库或使用已有的库来冻结对象,如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()的对象。
Javascript对象解冻
修改 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 }
锁定对象的方法
- Object.preventExtensions()
no new properties or methods can be added to the project 对象不可扩展, 即不可以新增属性或方法, 但可以修改/删除
- Object.seal()
same as prevent extension, plus prevents existing properties and methods from being deleted 在上面的基础上,对象属性不可删除, 但可以修改
- Object.freeze()
same as seal, plus prevent existing properties and methods from being modified 在上面的基础上,对象所有属性只读, 不可修改
以上三个方法分别可用Object.isExtensible(), Object.isSealed(), Object.isFrozen()来检测
Object.freeze( ) 阻止Vue无法实现 响应式系统
当一个 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提升性能。
(学习视频分享:vuejs入门教程、编程基础视频)
站长资讯网