摘要:之所以会出现深浅拷贝的问题,实质上是由于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'

点击关注,第一时间了解华为云新鲜技术~

JS的深浅复制,原来如此!的更多相关文章

  1. JavaScript的深浅复制

    JavaScript的深浅复制 为什么有深复制.浅复制? JavaScript中有两种数据类型,基本数据类型如undefined.null.boolean.number.string,另一类是Obje ...

  2. js 对象深复制,创建对象和继承

    js 对象深复制,创建对象和继承.主要参考高级编程第三版,总结网上部分资料和自己的代码测试心得.每走一小步,就做一个小结. 1.对象/数组深复制 一般的=号传递的都是对象/数组的引用,如在控制台输入 ...

  3. 详谈OC(object-c)深浅复制/拷贝-什么情况下用retain和copy

    读前小提示:对于深浅复制有一个清楚的了解,对于学习oc的朋友来说,至关重要.那么首先,我们要明白深浅复制是如何定义的呢.这里为了便于朋友们理解,定义如下. 浅 复 制:在复制操作时,对于被复制的对象的 ...

  4. OC-深浅复制

    [OC学习-26]对象的浅拷贝和深拷贝——关键在于属性是否可被拷贝 对象的拷贝分为浅拷贝和深拷贝, 浅拷贝就是只拷贝对象,但是属性不拷贝,拷贝出来的对象和原来的对象共用属性,即指向同一个属性地址. 深 ...

  5. Objective-c 深浅复制

    深浅复制的定义: 浅复制:在复制时,对于被复制对象的每一层都是指针复制. 深复制:在复制时,对于被复制的对象至少有一层是对象复制. 完全复制:在复制时,对于被复制对象的每一层都是完全复制. retai ...

  6. [置顶] js中如何复制一个对象,如何获取所有属性和属性对应的值

    在js中如何复制一个对象,例如如下一个js对象. 如果知道这个对象的所有属性自然就可以重新new一个,然后对每个属性赋值,就可以做到,但如果不知道呢?如何创建一个内容相同 的对象呢? var obj= ...

  7. Python基础之列表深浅复制和列表推导式

    一.列表深浅复制: 浅拷贝内存图如下: 深拷贝内存图如下: 二.列表推导式: 实例: """ 列表推导式 练习:exercise01 """ ...

  8. Cocos Creator JS web平台复制粘贴代码(亲测可用)

    Cocos Creator JS web平台复制粘贴代码(亲测可用) 1 webCopyString: function(str){ var input = str; const el = docum ...

  9. C# 深浅复制 MemberwiseClone(转载)

    最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考MSDN:https://docs.microsoft.com/zh-cn/dotnet/api/syst ...

  10. C# 深浅复制 MemberwiseClone

    学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考 ...

随机推荐

  1. InnoDB 存储引擎之 Buffer Pool

    Mysql 5.7 InnoDB 存储引擎整体逻辑架构图 一.Buffer Pool 概述 InnoDB 作为一个存储引擎,为了降低磁盘 IO,提升读写性能,必然有相应的缓冲池机制,这个缓冲池就是 B ...

  2. 面试题:MySQL事务的ACID如何实现?

    大家好,我是[码老思],事务是一个数据库绕不开的话题,今天和大家一起聊聊. 事务是什么? 事务(Transaction)是并发控制的基本单位.所谓的事务呢,它是一个操作序列,这些操作要么都执行,要么都 ...

  3. Python:基础&爬虫

    Python:基础&爬虫 Python爬虫学习(网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本.另 ...

  4. 阿里发布AI编码助手:通义灵码,兼容 VS Code、IDEA等主流编程工具

    今天是阿里云栖大会的第一天,相信场外的瓜,大家都吃过了.这里就不说了,有兴趣可以看看这里:云栖大会变成相亲现场,最新招婿鄙视链来了... . 这里主要说说阿里还发布了一款AI编码助手,对于我们开发者来 ...

  5. langchain中的chat models介绍和使用

    简介 之前我们介绍了LLM模式,这种模式是就是文本输入,然后文本输出. chat models是基于LLM模式的更加高级的模式.他的输入和输出是格式化的chat messages. 一起来看看如何在l ...

  6. 本地MinIO存储服务Java远程调用上传文件

    MinIO是一款高性能.分布式的对象存储系统,它可以100%的运行在标准硬件上,即X86等低成本机器也能够很好的运行MinIO.它的优点包括高性能.高可用性.易于部署和管理.支持多租户等. Cpola ...

  7. K8s 多租户方案的挑战与价值

    在当今企业环境中,随着业务的快速增长和多样化,服务器和云资源的管理会越来越让人头疼.K8s 虽然很强大,但在处理多个部门或团队的业务部署需求时,如果缺乏有效的多租户支持,在效率和资源管理方面都会不尽如 ...

  8. 大白话说Python+Flask入门(六)Flask SQLAlchemy操作mysql数据库

    写在前面 这篇文章被搁置真的太久了,不知不觉拖到了周三了,当然,也算跟falsk系列说再见的时候,真没什么好神秘的,就是个数据库操作,就大家都知道的CRUD吧. Flask SQLAlchemy的使用 ...

  9. [ABC262A] World Cup

    Problem Statement A sport event is held in June of every year whose remainder when divided by $4$ is ...

  10. Springboot快速集成阿里云RocketMq

    前言 随着互联网的兴起,越来越多的用户开始享受科技带来的便利,对于服务的压力也日益增大,随即便有了高并发.高性能.高可用等各种解决方案,这里主要介绍RocketMq的集成方法.(文末附源码地址) 正文 ...