亲宝软件园·资讯

展开

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,报错,不能修改地址

二者对比总结

3.常用功能

下面简单列举下Object.freeze的常用小功能吧。

功能一:冻结目标对象

看到这,估计有人要喷了。冻结对象不是很明显的?还要介绍一遍?大哥,大姐们稍安勿躁。容我慢慢狡辩。

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。

加载全部内容

相关教程
猜你喜欢
用户评论