JS的深浅复制,原来如此!
摘要:之所以会出现深浅拷贝的问题,实质上是由于JS对基本类型和引用类型的处理不同。
本文分享自华为云社区《js的深浅复制,一看就明白》,作者: 鑫2020。
浅复制的意思
浅复制是仅仅对数据存放在栈内的引用的复制,没有复制引用指向堆内的内容。多个数据的浅复制,这复制多个引用,这多个引用共同指向堆内的同一个内容。当一个浅复制数据做出修改,即堆内的引用指向的内容发生修改,这时,其他通过引用指向这里的数据也会随着改变。
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
let objA = obj;
objA.a = 'a';
console.log(obj.a); // 'a'
console.log(objA.a); // 'a'
深复制的意思
深复制是指连同堆的内容一块复制,生成一个新的对象。多个深复制将是多个不同的对象,也就有不同的引用,也就指向不同的堆内容。
使用深复制的原由
在平常开发中,有时会有数据的传递与接收,当拿到传过来的数据后,难免需要对数据进行加工和改造,为了不破坏原有数据结构,这时就可以使用深复制拷贝数据,然后处理生成的新的数据。深复制也可以防止修改多个引用后引用混乱的问题,减少BUG的产生机会。
可实现深复制的几种方法
实现方式一:JSON的序列化与反序列化
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
let objA = JSON.parse(JSON.stringify(obj));//JSON的序列化与反序列化
objA.a = 'a';
console.log(obj.a); // 1
console.log(objA.a); // 'a'
虽然JSON的序列化与反序列化可以实现深复制,但有几个缺点需要注意:
1、date日期对象被转成日期日期字符串
2、没法访问到原型
3、复制不了undefined的属性
4、NAN和无穷被转为NULL
let d1 = new Date();
let obj = {
d1,
d2: undefined,
d3:NaN
}
let objD = JSON.parse(JSON.stringify(obj));
console.log(obj)
console.log(objD)
实现方式二:Object.assign()
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
let objA = Object.assign(obj);
objA.a = 'a';
console.log(obj.a); // 1
console.log(objA.a); // 'a'
虽然Object.assign()可以实现深复制,但对于更深层次的对象引用也是仅仅浅复制。
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
let objA = Object.assign(obj);
objA.c.c1 = 'c1'; //Object.assign()仅仅是一层深复制。
console.log(obj.c.c1); // 'c1'
console.log(objA.c.c1); // 'c1'
实现方式三:扩展运算符
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
let objA = {...obj};;
objA.a = 'a';
console.log(obj.a); // 1
console.log(objA.a); // 'a'
虽然扩展运算符"…"可以实现深复制,但对于更深层次的对象引用也是仅仅浅复制。
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
let objA = {...obj};
objA.c.c1 = 'c1'; //扩展运算符"..."同Object.assign()一样,仅仅是一层深复制,不能多层深复制。
console.log(obj.c.c1); // 'c1'
console.log(objA.c.c1); // 'c1'
实现方式四:使用递归
想要实现深复制,且实现多层深复制则可以使用递归循环复制。
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
const ReCopy = function (paramter) {
let target = null;
let isObject = paramter.constructor === Object;
let isArray = paramter.constructor === Array;
if (isObject || isArray) {
target = Array.isArray(paramter) ? [] : {};
for (let i in paramter) {
target[i] = ReCopy(paramter[i]);
}
} else {
target = paramter;
}
return target;
}
let objA = ReCopy(obj);
objA.c.c1 = 'c1';
console.log(obj.c.c1); // 10
console.log(objA.c.c1); // 'c1'
ladash深拷贝
lodash深复制是更专业的深复制方式。
- 安装lodash
先初始化,生成package.json文件,然后使用一下命令安装。npm i -S lodash
- 引入lodash
var _ = require('lodash');
- 使用lodash
let obj = {
a:1,
b:2,
c:{
c1:10,
c2:20
}
}
let objA = _.cloneDeep(obj);
objA.c.c1 = 'c1';
console.log(obj.c.c1); // 10
console.log(objA.c.c1); // 'c1'
开发者之家
华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态...
推荐阅读
【贺】来自开发者的点赞,华为云开发者联盟入选 2022 中国技术品牌影响力企业榜
2023 年 1 月 4 日,中国技术先锋年度评选 | 2022 中国技术品牌影响力企业榜单正式发布。作为中国领先的新一代开发者社区,SegmentFault 思否依托数百万开发者用户数据分析,各科技企业在国内技术领域的行为及影...
华为云开发者联盟阅读 355
从零搭建 Node.js 企业级 Web 服务器(零):静态服务
过去 5 年,我前后在菜鸟网络和蚂蚁金服做开发工作,一方面支撑业务团队开发各类业务系统,另一方面在自己的技术团队做基础技术建设。期间借着 Node.js 的锋芒做了不少 Web 系统,有的至今生气蓬勃、有的早已夭折...
乌柏木赞 148阅读 12.1k评论 10
JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...
jenemy赞 46阅读 5.9k评论 12
从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...
乌柏木赞 65阅读 6.1k评论 16
再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...
libinfs赞 39阅读 6.3k评论 12
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...
乌柏木赞 42阅读 7.3k评论 6
从零搭建 Node.js 企业级 Web 服务器(二):校验
校验就是对输入条件的约束,避免无效的输入引起异常。Web 系统的用户输入主要为编辑与提交各类表单,一方面校验要做在编辑表单字段与提交的时候,另一方面接收表单的接口也要做足校验行为,通过前后端共同控制输...
乌柏木赞 33阅读 6.1k评论 9
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。