关于 JavaScript 对象不变性,你了解吗?

1. 基本概念

在 JavaScript 语言中,不变性(Immutability)是一个重要的概念。它指的是对象一旦创建后其状态就不能改变。在函数式编程中,不变性是实现纯函数的基础,因为它可以确保函数的输出只依赖于输入参数,而不受外部状态的影响。对于 JavaScript 这样的多范式语言来说,理解并应用不变性可以带来代码的可预测性和易于测试等好处。

对象不变性在任何编程语言中都是一个重要的概念。它会限制对象修改并防止不需要的更改。简而言之,对象的不变性就是将它的状态变为只读的,下面就来看看在 JavaScript 中的对象不变性。 ​

在 JavaScript 中,一个对象可以有一个或多个属性。每个属性都是一个键值对,下面是一个对象:

const user = {name: "张三",age: 24,
};

这里使用 const 关键字定义了一个对象,它具有两个属性。默认情况下,对象是可变的,也就是说,我们可以给对象添加新属性,修改现有属性或者删除已有属性。而在某些情况下,我们可能希望对象是不可变的,即不能添加新属性,也不能修改和删除已有属性。

2. 冻结对象 Object.freeze()

使用Object.freeze()方法可以使一个对象变为不可变的。这意味着不能添加新属性,也不能修改现有属性的值,而且该对象的原型也是不可变的。

const obj = Object.freeze({ key: "value" });
obj.key = "new value"; // 尝试修改将失败,obj.key 仍为 'value'

顾名思义,freeze() 就是用来冻结对象的。只需要将不想被更改的对象传递给它,就会返回该对象的不可变版本:

const user = {name: "张三",age: 24,
};const freezeUser = Object.freeze(user);
freezeUser.age = 18;
console.log(freezeUser.age); // 24

这时,新的对象就不可变了,相当于被冻结了。 ​

在 JavaScript 了,提供了一个 Object.isFrozen(),它可以用来判断一个对象是否被冻结:

Object.isFrozen(user); // false
Object.isFrozen(freezeUser); // true

需要注意的是, Object.freeze() 方法不会影响嵌套对象,对于嵌套对象,冻结后仍然是可以操作的:

const user = {name: "张三",age: 24,article: {title: "learn javascript",number: 1234,},
};const freezeUser = Object.freeze(user);
freezeUser.age = 18;
freezeUser.article.number = 666;
console.log(freezeUser.age); // 24
console.log(freezeUser.article.number); // 666

可以看到,使用 Object.freeze() 方法冻结的对象,age 是不可以更改的,但是嵌套对象的 number 属性还是可以修改的。如果需要冻结嵌套对象使其不可变,就需要使用循递归来逐级冻结,下面是一个简单的递归冻结实现:

const deepFreeze = (obj) => {Object.keys(obj).forEach((prop) => {if (typeof obj[prop] === "object") {deepFreeze(obj[prop]);}});return Object.freeze(obj);
};deepFreeze(user);

Object.freeze()方法除了可以用来冻结对象以外,还可以用于冻结数组,使其不可变:

const number = [1, 2, 3, 4, 5];
const freezeNumber = Object.freeze(number);
freezeNumber.push(6);

此时就会报错了:

VM210:3 Uncaught TypeError: Cannot add property 5, object is not extensible

3. 密封对象 Object.seal()

Object.seal() 顾名思义就是密封对象,它是另一种使对象不可变的方法。相对于 freeze(),Object.seal() 方法仅保护对象不能添加和删除属性,它允许更新现有的属性。

const user = {name: "张三",age: 24,
};const sealUser = Object.seal(user);
sealUser.age = 18;
delete sealUser.name;
console.log(sealUser); // {name: '张三', age: 18}

可以看到,我们识图删除对象中的 name 属性,删除失败;而修改已有的 age 属性,修改成功。 ​

Object.seal()方法和 Object.freeze()一样,对于嵌套的对象,是无法实现不可变的,如果想要实现,同样要使用递归来一层层来密封对象。 ​

JavaScript 同样提供了一个 Object.isSealed() 方法来确认对象的密封状态:

Object.isSealed(user); // false
Object.isSealed(sealUser); // true

4. const 关键字

你是否会认为,使用 const 关键字也能达到相同的结果呢?实际上,他们是不一样的,当我们使用 const 关键字来创建对象时,它会阻止我们重新分配值,但是我们可以更新、添加、删除已有对象的属性:

const user = {name: "张三",age: 24,
};delete user.age;
user.height = 180;
user.name = "hello";
console.log(user); // {name: 'hello', height: 180}

而如果我们给 user 重新赋值,那么就会报错了:

Uncaught TypeError: Assignment to constant variable.

因此,const 关键字仅仅是提供了赋值的不变性,而不会提供值的不变性(对于对象来说)。

5. 使用不可变库

如 Immutable.js 提供了一套完整的不可变数据结构,包括 List、Map、Set 等。这些数据结构在被“修改”时实际上会返回一个新的实例,而不是直接修改原对象。

const { Map } = require("immutable");
let map1 = Map({ a: 1, b: 2 });
let map2 = map1.set("b", 50); // 返回新的Map实例
console.log(map1.get("b")); // 输出 2
console.log(map2.get("b")); // 输出 50

6. 浅克隆与深克隆

通过创建对象的副本来进行“修改”,这种方式适用于简单的对象结构。对于复杂的嵌套对象,则需要进行深克隆。

function shallowClone(obj) {return { ...obj };
}function deepClone(obj) {return JSON.parse(JSON.stringify(obj));
}

7. 总结

本文简单介绍了几种可以用于使 JavaScript 不可变的方法。简而言之,Object.seal()方法会阻止更新、删除和向对象添加新属性,Object.seal()只会阻止添加和删除属性。、

除此之外,JavaScript 还提供了一个 Object.preventExtensions()方法,该方法可以让一个对象变的不可扩展,也就是永远不能再添加新的属性。

const user = {name: "张三",age: 24,
};const newUser = Object.preventExtensions(user);
newUser.height = 180;
console.log(newUser); //  {name: '张三', age: 24}

不变性的优点

  1. 减少副作用:不可变对象不会因为程序其他部分的修改而发生改变,这减少了潜在的副作用。

  2. 提高并发安全性:在多线程环境中,不可变对象不需要额外的同步机制来保证数据的一致性。

  3. 简化调试:由于对象的状态不会改变,因此更容易追踪到问题发生的源头。

  4. 增强缓存能力:如果一个对象是不可变的,那么它的哈希值可以在创建时计算一次,之后就不再需要重新计算。

  5. 优化性能:某些情况下,使用不可变数据结构可以避免不必要的复制操作,从而提高性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/13730.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

AOA-LSTM多输入时序预测|算术优化算法-长短期神经网络|Matlab

目录 一、程序及算法内容介绍: 基本内容: 亮点与优势: 二、实际运行效果: 三、方法原理介绍: 四、完整程序数据下载: 一、程序及算法内容介绍: 基本内容: 本代码基于Matlab平…

【金猿案例展】上海汽检——智能网联自动驾驶交通事故原因分析服务平台

‍ 零数科技案例 本次项目案例由零数科技投递并参与“数据猿年度金猿策划活动——2024大数据产业年度创新服务企业榜单/奖项”评选。 大数据产业创新服务媒体 ——聚焦数据 改变商业 智能网联汽车作为未来交通出行的重要载体,其自动驾驶功能的快速发展为车辆的安全…

基于51单片机的电风扇控制系统proteus仿真

地址:https://pan.baidu.com/s/11xIpPrV8Xl5Wymk_gxPxPA 提取码:1234 仿真图: 芯片/模块的特点: AT89C52/AT89C51简介: AT89C52/AT89C51是一款经典的8位单片机,是意法半导体(STMicroelectron…

DAY110代码审计-PHP框架开发篇ThinkPHP版本缺陷不安全写法路由访问利用链

https://blog.csdn.net/m0_60571842/article/details/139057898 看这个原作者 知识点: 1、PHP框架学习-ThinkPHP-架构&调试&路由&接受2、PHP框架审计-ThinkPHP-不安全写法&版本漏洞 框架审计总结方向: 1、版本不安全写法怎么检测 -本…

网络安全技术在能源领域的应用

摘要 随着信息技术的飞速发展,能源领域逐渐实现了数字化、网络化和智能化。然而,这也使得能源系统面临着前所未有的网络安全威胁。本文从技术的角度出发,探讨了网络安全技术在能源领域的应用,分析了能源现状面临的网络安全威胁&a…

Ubuntu上nginx常用命令

错误截图 启用nginx systemctl start nginx 停止 systemctl stop nginx 重启 systemctl restart nginx 检查nginx配置文件是否正确 nginx -t -c /etc/nginx/nginx.conf 修改配置文件后,重新加载配置文件命令 nginx -s reload 查看nginx服务状态&#xff0c…

Shell编程之正则表达式与文本处理器

Shell编程之正则表达式与文本处理器 文章目录 Shell编程之正则表达式与文本处理器正则表达式正则表达式概述正则表达式的定义 基础正则表达式grep创建测试文件查找特定字符**查找行首与行位****查找任意字符和重复字符****查找连续字符范围**扩展正则表达式 扩展正则表达式文本…

机器情绪及抑郁症识别算法

🏡作者主页:点击! 🤖编程探索专栏:点击! ⏰️创作时间:2024年11月12日11点25分 点击开启你的论文编程之旅https://www.aspiringcode.com/content?id17231829233829 情感识别:多…

基于Java Springboot在线教育学习系统

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术:Html、Css、Js、Vue、Element-ui 数据库:MySQL 后端技术:Java、Spring Boot、MyBatis 三、运行环境 开发工具:IDEA/eclipse 数据…

Spring Boot编程训练系统:开发流程与技巧

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式,是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示: 图4-1系统工作原理…

【SSL-RL】自监督强化学习:自预测表征 (SPR)算法

📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅…

Station Editor更新和版本回退

一、更新 第一步点击import 第二步 第三步 第四步 第五步 第六步 第七步 第八步 第九步 第十步 第十一步 第十二步 第十三步 、 第十四步 第十五步 第十六步 点击完update才能继续下一步 第十七步 第十八步,结束出来刷新一下就可以了

如何利用亚马逊自养号测评,实现店铺稳定出单的策略

企业的发展通常会经历一系列阶段,从起步、立足市场,到迅速扩张、达到顶峰,再到可能的市场适应或转型期,亚马逊平台上的店铺发展路径亦是如此。为了确保店铺能够长期立足于市场,关键在于有效利用其快速成长期和成熟期&a…

【Linux】基础IO及文件描述符相关内容详细梳理

0. C语言文件I/O 在C语言中,我们学习了相关函数来读写文件,例如:fopen,fwrite,fread,fprintf等, 在C语言中文件的打开方式: r Open text file for reading. …

DIY了一台无人机,用全志T113芯片

‌无人机飞控是无人机的核心部分,一般包括传感器、机载计算机和伺服作动设备三大部分,能否在对重量和体积有严苛要求的无人机结构上部署具有稳定功能的飞控,是影响无人机飞行表现的重要因素。 基于此,作者就基于全志T113-S3设计了…

vue+springboot天气预测大数据2+1架构|必须带有管理端和数据库爬虫等|机器学习预测使用

文末有CSDN官方提供的麦麦的联系微信! 文末有CSDN官方提供的麦麦的联系微信! 🩷编号:R04 🩷架构:21架构,大屏端管理端后端,vuespringbotmysql 🩵全新开发,代码完整&#…

Tofu AI视频处理模块视频输入配置方法

应用Tofu产品对网络视频进行获取做视频处理时,首先需要配置Tofu产品的硬件连接关系与设备IP地址、视频拉流地址。 步骤1 Tofu设备点对点直连或者通过交换机连接到电脑,电脑IP配置到与Tofu默认IP地址同一个网段。 打开软件 点击右上角系统设置 单击左侧…

地区级的可视化地图不设计,进来看看超炫的样式吧

地区级的可视化地图如果精心设计,能带来超炫的视觉效果。可以运用丰富的色彩来区分不同区域,使地图更加生动鲜明。 采用立体的图形设计,让地形地貌更加直观。添加动态效果,如数据的实时更新流动、热点区域的闪烁等,增…

《AI 使生活更美好》

《AI 使生活更美好》 当我们步入科技腾飞的时代,人工智能(AI)如同一颗璀璨的新星,照亮了我们生活的每一个角落。它以惊人的速度改变着我们的世界,从医疗到教育,从交通到娱乐,AI 正以前所未有的力…

数据结构 ——— 链式二叉树的销毁(释放)

目录 链式二叉树示意图 手搓一个链式二叉树 代码实现 示意图 手搓一个链式二叉树 代码演示: // 数据类型 typedef int BTDataType;// 二叉树节点的结构 typedef struct BinaryTreeNode {BTDataType data; //每个节点的数据struct BinaryTreeNode* left; //指向…