ES6新语法Object.freeze和Object.seal基本使用
前端兰博 人气:0引言
随着ES6新语法的不断迭代更新,已经出现了许多常用的工具api。今天我将为大家推荐两款明星api,它们就是Object.freeze和Object.seal。究竟它两可以带给我们怎样的惊喜?我只能用两个字形容:NB
Object.freeze
1.基本使用
首先从单词含义分析 freeze代表冰冻,嗯那这个api就是冰冻/冻结对象的意思。接着我们看看mdn的解释吧
MDN官方解释
Object.freeze()
方法可以冻结一个对象。一个被冻结的对象再也不能被修改;冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。
官方就是踏马官方啊,解释的我都怀疑自己没学过语文,绕来绕去。其实它就说了一句话,Object.freeze可以让一个对象无法增加新属性,无法删除已有属性,无法修改已有属性。本质就是指目标对象只能读,其它任何操作都无效。
功能演示
通过Object.freeze处理的对象,进行删除,添加,修改都是无效的,并且在非严格模式下是不会报错的。
let obj = {name:"dzp",age:22} Object.freeze(obj) obj.name = "dzp2"//修改无效 delete obj.age//删除无效 obj.a = 1//添加无效 console.log(obj)// {name:"dzp",age:22}
拓展
看到上面的操作,部分童鞋可能疑问这个对数组可以冻结?数组在js里面也属于对象,所以数组也是可以冻结的。冻结后的数组也是只读的
let arr = [1] Object.freeze(arr) arr[0] = 2//无效 arr.push(2)//无效 arr.shift()//无效 console.log(arr)//[1]
2.Object.freeze与const对比
看到freeze大家肯定会联想到另一个api,它就是const。它们感觉都有冻结的意思,其实二者设计初衷和功能点还是相差甚远。
const通常我们用它修饰普通变量,用const定义的普通变量值无法修改。而const定义的对象地址无法修改,其内部的属性仍然是可变的。
const定义普通变量
const a = 10 a = 20//error,报错无法修改
const定义对象
const obj = {a:1} obj.a = 2//ok obj = {}//error,报错,不能修改地址
二者对比总结
- const通常定义普通变量,而Object.freeze通常定义对象
- const定义普通变量时,值无法修改。定义对象时,地址无法修改,但是对象内部属性可以任意改变。
- Object.freeze修饰的对象只能读,其它任何操作都是无效的。
- Object.freeze修饰的对象可以改变地址,改变地址后的对象就失去了freeze控制了,当然这个操作是毫无意义的。
3.常用功能
下面简单列举下Object.freeze的常用小功能吧。
- 冻结目标对象(默认是浅冻结)
- vue2中数据的性能优化
功能一:冻结目标对象
看到这,估计有人要喷了。冻结对象不是很明显的?还要介绍一遍?大哥,大姐们稍安勿躁。容我慢慢狡辩。
Object.freeze冻结对象是浅度冻结,并非深度冻结。通常我们希望一个对象数据是完全只读的。而单纯的使用Object.freeze是无法实现对象完全可读。
浅冻结示例
let obj = {name:"dzp",a:{b:1}} Object.freeze(obj) obj.name = "dzp2"//无法修改 obj.a.b = 2//可以修改 console.log(obj)//{name:"dzp",a:{b:2}}
看到上面的结果大家就很容易发现,freeze对对象的冻结只能作用到第一层上,当对象层级大于等于2时,后面的冻结就失效了。这其实就是浅冻结,浅冻结和浅比较可以理解成一类,其中React函数组件通常我们会使用memo进行优化,此处的设计就是利用浅比较完成的。
深度冻结对象
上面我们知道了用freeze只能对对象进行浅度冻结,无法真正冻结一个多层嵌套对象的对象。通常我们需要自己设计深冻结。如下例子内部出现了Object.seal。大家不必着急,可以先看完后面Object.seal的介绍,然后再继续看深冻结例子。(Object.seal后面讲更清晰)
功能二:vue2数据优化
Object.freeze是如何对vue2的数据做到优化?我们清楚vue2的data数据都是具备响应式的,数据通过defineProperty完成响应式设置,但是这本身耗费了一定性能。如果我们有接口数据仅仅做展示并且数目较多。那么对其进行响应式监听无疑是没必要的。但是vue2渲染界面的数据都是响应式的,如何消除数据的响应式?Object.freeze就可以做到消除响应式。
<template> <div id="app"> <div v-for="item in list" :key=item>{{item}}</div> <div @click="changeData()">修改数据</div> </div> </template> <script> export default { name: 'App', data() { return { list:[] } }, mounted(){ //模拟接口获取数据 setTimeout(() => { this.list.push(...[1,2,3,4,5]) //将数据取消响应式 Object.freeze(this.list) }, 2000); }, methods:{ changeData () { this.list.push(6) } } } </script>
效果
如果是未添加Object.freeze的数组,此处肯定是正常显示6个,但是通过freeze我们直接消除了数据的响应式,让这个数据只能展示而无法修改,同时也一定程度提升了性能。
Object.seal
Object.seal其实没有Object.freeze使用的频繁,但是一些工具还是需要它的配合,例如使用Object.seal可以模拟Object.freeze的浅度和深度的对象监听。
1.基本使用
MDN介绍
Object.seal()
方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变。
还是简单总结官方的话语:Object.seal修饰的对象无法添加或者删除属性,可以修改可以读取。
简单使用
let obj = {name:"dzp"} Object.seal(obj) obj.age = 22//无法添加 obj.name = "dzp2"//可以修改 delete obj.name//无法删除 console.log(obj)//{name:"dzp2"}
值得注意的是Object.freeze和Object.seal都是对对象浅控制,只作用于第一层。大于等于2层级的对象不受控制。
let obj = {name:'dzp',a:{b:1}} delete obj.a.b console.log(obj)//{ name: 'dzp', a: {} }
2.模拟Object.freeze
模拟Object.freeze是一道经典的面试手撕代码题,我们可以借助Object.seal轻松的完成设计。整体设计还是比较简单,使用seal控制对象不可以增加和删除属性。然后使用Object.defineProperty让对象无法修改属性
function myFreeze(obj) { if(obj instanceof Object) { Object.seal(obj) for(let key in obj) { Object.defineProperty(obj,key,{ writable:false }) } } } let obj = {name:"dzp",a:{b:1}} myFreeze(obj) obj.name = "dzp2"//无效 delete obj.name//无效 obj.age = 22//无效 obj.a.b = 2//有效,只冻结第一层 console.log(obj)//{name:"dzp",a:{b:2}}
3.模拟Object.freeze,同时保证对象深冻结
深度冻结在浅度冻结的基础上,只需要加一个递归就可以实现,整体设计十分清晰简单。
function myFreeze(obj) { if(obj instanceof Object) { Object.seal(obj) for(let key in obj) { Object.defineProperty(obj,key,{ writable:false }) myFreeze(obj[key]) } } } let obj = {name:"dzp",a:{b:1}} myFreeze(obj) obj.name = "dzp2"//无效 delete obj.name//无效 obj.age = 22//无效 obj.a.b = 2//无效,深冻结了 console.log(obj)//{name:"dzp",a:{b:2}}
总结
终于总结完了Object.freeze和Object.seal。
加载全部内容