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'
JS的深浅复制,原来如此!的更多相关文章
- JavaScript的深浅复制
JavaScript的深浅复制 为什么有深复制.浅复制? JavaScript中有两种数据类型,基本数据类型如undefined.null.boolean.number.string,另一类是Obje ...
- js 对象深复制,创建对象和继承
js 对象深复制,创建对象和继承.主要参考高级编程第三版,总结网上部分资料和自己的代码测试心得.每走一小步,就做一个小结. 1.对象/数组深复制 一般的=号传递的都是对象/数组的引用,如在控制台输入 ...
- 详谈OC(object-c)深浅复制/拷贝-什么情况下用retain和copy
读前小提示:对于深浅复制有一个清楚的了解,对于学习oc的朋友来说,至关重要.那么首先,我们要明白深浅复制是如何定义的呢.这里为了便于朋友们理解,定义如下. 浅 复 制:在复制操作时,对于被复制的对象的 ...
- OC-深浅复制
[OC学习-26]对象的浅拷贝和深拷贝——关键在于属性是否可被拷贝 对象的拷贝分为浅拷贝和深拷贝, 浅拷贝就是只拷贝对象,但是属性不拷贝,拷贝出来的对象和原来的对象共用属性,即指向同一个属性地址. 深 ...
- Objective-c 深浅复制
深浅复制的定义: 浅复制:在复制时,对于被复制对象的每一层都是指针复制. 深复制:在复制时,对于被复制的对象至少有一层是对象复制. 完全复制:在复制时,对于被复制对象的每一层都是完全复制. retai ...
- [置顶] js中如何复制一个对象,如何获取所有属性和属性对应的值
在js中如何复制一个对象,例如如下一个js对象. 如果知道这个对象的所有属性自然就可以重新new一个,然后对每个属性赋值,就可以做到,但如果不知道呢?如何创建一个内容相同 的对象呢? var obj= ...
- Python基础之列表深浅复制和列表推导式
一.列表深浅复制: 浅拷贝内存图如下: 深拷贝内存图如下: 二.列表推导式: 实例: """ 列表推导式 练习:exercise01 """ ...
- Cocos Creator JS web平台复制粘贴代码(亲测可用)
Cocos Creator JS web平台复制粘贴代码(亲测可用) 1 webCopyString: function(str){ var input = str; const el = docum ...
- C# 深浅复制 MemberwiseClone(转载)
最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考MSDN:https://docs.microsoft.com/zh-cn/dotnet/api/syst ...
- C# 深浅复制 MemberwiseClone
学无止境,精益求精 十年河东,十年河西,莫欺少年穷 学历代表你的过去,能力代表你的现在,学习代表你的将来 最近拜读了大话设计模式:原型模式,该模式主要应用C# 深浅复制来实现的!关于深浅复制大家可参考 ...
随机推荐
- docker本地仓库-registry
Docker本地私有仓库实战: docker仓库主要用于存放docker镜像,docker仓库分为公有仓库和私有仓库,基于registry可以搭建本地私有仓库,使用私有仓库的优点如下: 节省网络带宽, ...
- could not chdir to home directory /home/user:permission denied /bin/bash:Permiss 的原因和解决方法
今天在vm上登录一个user 的时候,发现正确输入用户名和密码后弹出了这样的信息,登陆不上. 发现给出的信息中,permission denied 而 bin permiss; 这种情况表明自己给该用 ...
- 编写高性能C#代码 —— Span<T>
Span 提供任意内存的连续区域的类型安全和内存安全表示形式.它是在堆栈而不是托管堆上分配的ref结构,是对任意内存块的抽象 . 1.关于Span 在NET Core 2.1中首次引入 提供对任意内存 ...
- 旋转矩阵(leetcode4.7每日打卡)
给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节.请你设计一种算法,将图像旋转 90 度. 不占用额外内存空间能否做到? 示例 1: 给定 matrix = [ [1,2, ...
- 2020年第十一届蓝桥杯第二场C/C++ B组省赛题解
2020年第十一届蓝桥杯C/C++ B组省赛题解 试题A:门牌制作 [问题描述] 小蓝要为一条街的住户制作门牌号. 这条街一共有 \(2020\) 位住户,门牌号从 \(1\) 到 \(2020\) ...
- SQL Server 2000 创建角色,登陆用户,安全用户,批量授予权限
前言 我在2011年刚入门学习的时候,是从 SQL Server 2008 开始学的,再加上这些年较少接触 SQL Server 2000,因此对它不是很熟. 之前都是在 SQL Server 200 ...
- Python+Yolov8+ONNX实时缺陷目标检测
相比于上一篇Windows10+Python+Yolov8+ONNX图片缺陷识别,并在原图中标记缺陷,有onnx模型则无需配置,无需训练. 优化了程序逻辑,降低了程序运行时间,增加了实时检测功能 目录 ...
- 阿里云服务器docker系统 BUG
阿里云服务器docker系统 BUG购买了阿里云新加坡区的轻量服务器,安装的是docker专用系统,故障现象:docker镜像下载后,docker网络不通,docker端口不通,网络一直不通,通过防火 ...
- # [AI]多模态聚类能力助力AI完成自主意识测试
引言 探讨人工智能是否能形成自我意识,是一个当前AI领域一个重要而又复杂的问题.随着深度学习和强化学习技术的不断进步,计算机在视觉识别.语音识别和控制机器人等方面都已取得长足的进展,模拟和超越人类的一 ...
- 编辑linux服务启动命令(app-script.sh命令编写)
#!/bin/sh# 注:这里可替换为你自己的执行程序,其他代码无需更改APP_NAME=app-biz.jar #使用说明,用来提示输入参数usage() { echo "Usage: s ...