你连const怎样定义一个不能修改属性的对象都不知道?

901 阅读3分钟

前言

众所周知,在JavaScript中我们使用const声明一个常量时,一旦声明后就不能再重新赋值。但如果是对象或者是数组的属性与元素是可以被修改的。

那么怎么让const定义的对象的属性也不能被修改呢?? 太简单了,下面会区别情况进行讲解与演示。

基本示例

其实很简单就看你有没有想到了,主要还是考验对API的运用是否熟练,我们只需要结合使用Object.freeze()方法就可以实现了,Object.freeze()可以冻结对象,但只能冻结第一层属性。

因此我们先看看一层的对象示例

<html lang="zh">
  <head>
    <script>
      const testobj = {
        name: "天天鸭",
        age: 88,
      };

      Object.freeze(testobj);

      // 添加
      testobj["newgen"] = "new天";
      console.log("添加属性:", testobj.newgen);

      // 删除
      delete testobj.age;
      console.log("删除属性:", testobj.age);

      // 修改
      testobj.name = "月月鸭";
      console.log("修改属性:", testobj.name);
    </script>
  </head>
  <body>
    您好,我是天天鸭的示例
  </body>
</html>

先用const结合Object.freeze()后对其进行增删改操作,下面看看对应的打印效果

image.png

看效果可以知道增删改都不会生效并且不会输出任何错误,并且如果是添加会输出undefined

注意: 如果是严格模式会报错,如下图片所示。 image.png

在Vue框架中示例

如果在Vue3框架演示呢,你们觉得会有什么区别不???

下面直接上一个例子再说吧

<template>
  <div></div>
</template>

<script setup>
    const testobj = {
    name: "天天鸭",
    age: 88,
    };

    Object.freeze(testobj);

    // 添加
    testobj["newgen"] = "new天";
    console.log("添加属性:", testobj.newgen);

    // 删除
    delete testobj.age;
    console.log("删除属性:", testobj.age);

    // 修改
    testobj.name = "月月鸭";
    console.log("修改属性:", testobj.name);
</script>

Vue3中先用const结合Object.freeze()后对其进行增删改操作,再看看下面打印出来的效果

image.png

啊这....怎么来到这里就直接报错了呢??? 你们知道为什么不

其实原因有二

、是Vue 在开发模式下会默认使用严格模式,从而会导致报错。

、是因为与Vue框架的响应式和生命周期相关的原因,Vue的响应式机制会对对象进行依赖收集处理,从而实现响应式效果。当我们用Object.freeze冻结时,Vue会无法执行这些处理,因为已经冻结不可扩展了。

层级复杂的对象

我们日常使用对象处理数据的情况下不可能都是一层的简单结构,如果是层级很复杂的树状结构呢??毕竟Object.freeze()只能冻结一层。

那当然是用递归了,看看下面例子

<html lang="zh">
  <head>
    <script>
      function deepObjFreeze(obj) {
        // 如果已经是冻结的
        if (Object.isFrozen(obj)) {
          return obj;
        }
        // 获取所有属性
        const keys = Object.keys(obj);
        // 冻结每个
        keys.forEach((key) => {
          const value = obj[key];
          if (value && typeof value === "object" && !Object.isFrozen(value)) {
            deepObjFreeze(value);
          }
        });
        // 冻结当前
        return Object.freeze(obj);
      }

      const testObj = {
        name: "天天鸭",
        age: 88,
        details: {
          age: 25,
          gender: "new天",
        },
      };

      const frozenObj = deepObjFreeze(testObj);

      // 尝试修改属性
      frozenObj.name = "new名";
      frozenObj.details.age = 30;

      console.log(frozenObj);
    </script>
  </head>
  <body>
    您好,我是天天鸭的示例
  </body>
</html>

递归冻结后我们再去修改里面的属性,效果打印出来如下所示,不受任何影响。

image.png

小结

突然灵感一来,想起这个很考验基本功的小问题,没有难度,就是考我们对Object.freeze()方法的熟悉和结合需求的灵活性。

好啦文章这到这里,如果哪里写的不对或者有更好的建议欢迎指出哦。