JS 数组、对象的深拷贝
博客地址:https://ainyi.com/72
JavaScript 程序中,对于简单的数字、字符串可以通过 = 赋值拷贝
但是对于数组、对象、对象数组的拷贝,就有浅拷贝和深拷贝之分
浅拷贝就是当改变了拷贝后的数据,原数据也会相应改变
来说说深拷贝
数组深拷贝
遍历赋值
不推荐此方法
let a = [1, 2, 3]
let b = []
for (let val of a) {
b.push(val)
}
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]
slice()
数组方法 slice() 可从已有的数组中返回选定的元素
那么设置为 0,就是返回整个数组
let a = [1, 2, 3]
let b = a.slice(0)
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]
concat()
数组方法 concat() 连接一个或多个数组,并返回一个副本
那么不设置参数,就返回本数组
let a = [1, 2, 3]
let b = a.concat()
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]
ES6 方法
let a = [1, 2, 3]
let b = [...a]
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]
let a = [1, 2, 3]
let b = Array.from(a)
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]
对象深拷贝
Object.assign()
Object.assign(target, obj)
let a = { name: 'krry' }
let b = Object.assign({}, a)
b.name = 'lily'
a // { name: 'krry' }
b // { name: 'lily' }
注意使用 assign() 有如下特点:
- 不会拷贝对象继承的属性、不可枚举的属性、属性的数据属性/访问器属性
- 可以拷贝 Symbol 类型
扩展运算符
let a = { name: 'krry' }
let b = { ...a }
b.name = 'lily'
a // { name: 'krry' }
b // { name: 'lily' }
以上是简单数组、对象的深拷贝方法,但是对于二维数组、对象数组、对象里包含对象,以上方法均达不到深拷贝方法
以上只能达到数组、对象的第一层的深拷贝,对于里面的数组或对象属性则是浅拷贝,因为里面的内存地址只是拷贝了一份,但都是指向同一个地址
所以当改变数组、对象里的数组元素或对象,原数据依然会改变
二维数组、对象数组、多层对象的深拷贝
最常用的 JSON 序列化与反序列化
使用 JSON.parse(JSON.stringify(obj))
let a = [1, [2, {aa: 2}, [4]], {aa: 5, cc: { dd: 6 }}]
let b = JSON.parse(JSON.stringify(a)) // 完美
通过 JSON.stringify 实现深拷贝有几点要注意
- 拷贝的对象的值中如果有函数、undefined、symbol,则经过 JSON.stringify() 序列化后的 JSON 字符串中这个键值对会消失
- 无法拷贝不可枚举的属性,无法拷贝对象的原型链
- 拷贝 Date 引用类型会变成字符串
- 拷贝 RegExp 引用类型会变成空对象
- 对象中含有 NaN、Infinity 和 -Infinity,则序列化的结果会变成 null
- 无法拷贝对象的循环应用(即 obj[key] = obj)
自己实现深拷贝方法
function deepCopy(obj) {
let result = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object') {
result[key] = deepCopy(obj[key]); // 递归复制
} else {
result[key] = obj[key];
}
}
}
return result;
}
lodash 的深拷贝 cloneDeep
使用 lodash 插件的深拷贝方法
// 官方例子
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false
传送门:https://www.lodashjs.com/docs/4.17.5.html#cloneDeep
博客地址:https://ainyi.com/72
JS 数组、对象的深拷贝的更多相关文章
- 判断js数组/对象是否为空
/** * 判断js数组/对象是否为空 * isPrototypeOf() 验证一个对象是否存在于另一个对象的原型链上.即判断 Object 是否存在于 $obj 的原型链上.js中一切皆对象,也就是 ...
- js 数组对象深拷贝
js 数组对象深拷贝 结论:对象的拷贝不能采用直接赋值的方式. 背景 踩过的坑如下: formData本来是父组件传过来的,但是我不想直接用,于是我直接赋值给一个formDataCopy的对象. 但是 ...
- js 数组对象的操作方法
在jquery中处理JSON数组的情况中遍历用到的比较多,但是用添加移除这些好像不是太多. 今天试过json[i].remove(),json.remove(i)之后都不行,看网页的DOM对象中好像J ...
- 探究JS中对象的深拷贝和浅拷贝
深拷贝和浅拷贝的区别 在讲深拷贝和浅拷贝的区别之前,回想一下我们平时拷贝一个对象时是怎么操作的?是不是像这样? var testObj1 = {a: 1, b:2}, testObj2=testObj ...
- JS数组&对象遍历
遍历的总结,经常用到的,希望帮助你我成长. JS数组遍历: 1,普通for循环 var arr = [1,2,3,4,9]; for ( var i = 0; i <arr.length; i+ ...
- js数组对象排序详解
一.js对象遍历输出的时候真的是按照顺序输出吗? 下边就来实践一下: var obj={'3':'ccc',name:'abc',age:23,school:'sdfds',class:'dfd',h ...
- JS 数组对象
定义数组: 数组对象用来在单独的变量名中存储一系列的值. 创建一个数组有三种方法. 1: 常规方式: var myCars=new Array(); myCars[0]="Saab" ...
- 【原】js数组对象去重最简单的方法
简单的数组去重是比较简单的,方法也特别多,如给下面的数组去重: let arr = [1,2,2,4,9,6,7,5,2,3,5,6,5] 最常用的可以用for循环套for循环,再用splice删除重 ...
- js数组对象深度复制
var deepCopy = function(o) { if (o instanceof Array) { var n = []; for (var i = 0; i < o.length; ...
- Js 数组对象排序
1.定义函数 /** * 数组对象排序函数 * @param {any} name 排序字段 * @param {any} order 升.降(这里事true.false记得处理下) */ var b ...
随机推荐
- Solr的中英文分词实现
对于Solr应该不需要过多介绍了,强大的功能也是都体验过了,但是solr一个较大的问题就是分词问题,特别是中英文的混合分词,处理起来非常棘手. 虽然solr自带了支持中文分词的cjk,但是其效果实在不 ...
- MySQL-5.6.36-多实例-部署(编译版)
MySQL多实例_沁贰百科 注:部署双实例前,首先需要部署单实例,单实例部署详情如下: https://www.cnblogs.com/wangqiner/p/9081002.html 1.如已经安装 ...
- Mtcnn进行人脸剪裁和对齐B
Mtcnn进行人脸剪裁和对齐 from scipy import misc import tensorflow as tf import detect_face import cv2 # import ...
- 基于SpringBoot从零构建博客网站 - 确定需求和表结构
要确定一个系统的需求,首先需要明确该系统的用户有哪些,然后针对每一类用户,确定其需求.对于博客网站来说,用户有3大类,分别是: 作者,也即是注册用户 游客,也即非注册用户 管理员,网站维护人员 那么从 ...
- 女皇武则天:我不愿被 extends
01. 利用继承,我们可以基于已存在的类构造一个新类.继承的好处在于,子类可以复用父类的非 private 的方法和非 private 成员变量. is-a 是继承的一个明显特征,就是说子类的对象引用 ...
- vs中开发web站点使IIS Express支持局域网连接
vs中开发web站点使IIS Express支持局域网连接 在开发webapi的时候,客户端设备都会使用局域网的地址访问webapi,有时候需要调试api.这个时候就需要使用一些技巧了,这里我记录了我 ...
- 目标检测之R-CNN系列
Object Detection,在给定的图像中,找到目标图像的位置,并标注出来. 或者是,图像中有那些目标,目标的位置在那.这个目标,是限定在数据集中包含的目标种类,比如数据集中有两种目标:狗,猫. ...
- spring boot整合mybatis方式一
方式一: 导入maven依赖: <!--web依赖配置--> <dependency> <groupId>org.springframework.boot</ ...
- 设计模式 | 建造者模式/生成器模式(builder)
定义: 将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 结构:(书中图,侵删) 一个产品类 一个指定产品各个部件的抽象创建接口 若干个实现了各个部件的具体实现的创建类 一个 ...
- 设计模式 | 原型模式(prototype)
定义: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. 结构:(书中图,侵删) 一个申明克隆自己的接口 若干具体的需要克隆自己的类 这个结构很简单,而且在Java中那个接口是不需 ...