带你了解JS对象的浅拷贝和深拷贝

原文链接:https://note.noxussj.top/?source=helloworld


以下主要介绍了正常情况下的拷贝、浅拷贝、深拷贝三种方式的区别。

  • 正常拷贝:复制一个对象,它们的内存地址是相同的
  • 浅拷贝:拷贝对象的第一层属性
  • 深拷贝:拷贝对象多层的属性

正常拷贝

假设我们要复制一个对象,如果不对其进行深拷贝,那么改变其中一个对象后,另外一个对象也会跟着改变。

1const a = { 2 age: 20 3} 4 5const b = a 6 7b.age = 30 8 9console.log(a.age) // 30

这并不是我们想要的效果,所以想要复制一个全新的对象时,我们可以通过浅拷贝来实现。

浅拷贝

方式一

1const a = { 2 name: 'xiaoming', 3 age: 20 4} 5 6const b = { name: a.name, age: a.age } 7 8b.age = 30 9 10console.log(a.age) // 20

这种方式就不太灵活,要拷贝的对象属性越多,自己手写的属性就越多。

方式二

1const a = { 2 name: 'xiaoming', 3 age: 20 4} 5 6const b = {} 7 8for (const key in a) { 9 b[key] = a[key] 10} 11 12b.age = 30 13 14console.log(a.age) // 20

通过遍历的方式,无论旧对象的属性有多少个,都可以自动拷贝到新的对象上。 以上方式由于是浅拷贝只能拷贝对象的一层属性,对于对象有多层属性依然是存在同样的问题。

1const a = { 2 name: 'xiaoming', 3 age: 20, 4 children: { 5 name: 'libai', 6 age: 20 7 } 8} 9 10const b = {} 11 12for (const key in a) { 13 b[key] = a[key] 14} 15 16b.children.age = 30 17 18console.log(a.children.age) // 30

我们把对象 b 的 children 属性改变后,对象 a 的 children 属性也会跟着改变,这也不是我们想要的效果,所以我们可以通过对象的深度拷贝实现(拷贝无限深的层级)。

深拷贝

方式一

1const a = { 2 name: 'xiaoming', 3 age: 20, 4 children: { 5 name: 'libai', 6 age: 20 7 } 8} 9 10const b = JSON.parse(JSON.stringify(a)) 11 12b.children.age = 30 13 14console.log(a.children.age) // 20

通过 JSON 类来实现,实现起来非常简单,首先把对象转成 JSON 字符串,然后在把 JSON 字符串转成对象。但是这种方式依然存在问题,假设我的对象里面有 function 属性等其他非值类型属性,那就无法拷贝了。

1const a = { 2 name: 'xiaoming', 3 age: 20, 4 children: { 5 name: 'libai', 6 age: 20 7 }, 8 eat: function () { 9 console.log('i am eat') 10 } 11} 12 13const b = JSON.parse(JSON.stringify(a)) 14 15console.log(b.eat) // undefined

方式二

使用递归(深度优先搜索)方式,这种就是最稳定的一种方式,但是实现起来也是比较复杂,就是将对象的每一层属性都遍历出来,赋值给新的对象。

这里简单介绍一下什么是递归,就是在一个函数内部中再次调用自己,当达到一定条件后停止调用。

1// 类型字典 2function type(data) { 3 let dist = { 4 '[object Array]': 'array', 5 '[object Object]': 'object', 6 '[object Number]': 'number', 7 '[object Function]': 'function', 8 '[object String]': 'string', 9 '[object Null]': 'null', 10 '[object Undefined]': 'undefined' 11 } 12 13 return dist[Object.prototype.toString.call(data)] 14} 15 16// 深度优先遍历 17function dfs(data) { 18 let newData 19 20 if (type(data) === 'array') { 21 newData = [] 22 data.map((item, index) => { 23 newData[index] = dfs(item) 24 }) 25 } else if (type(data) === 'object') { 26 newData = {} 27 Object.keys(data).map((item) => { 28 newData[item] = dfs(data[item]) 29 }) 30 } else { 31 newData = data 32 } 33 34 return newData 35}
1const a = { 2 name: 'xiaoming', 3 age: 20, 4 children: { 5 name: 'libai', 6 age: 20 7 }, 8 eat: function () { 9 console.log('i am eat') 10 } 11} 12 13const b = dfs(a) 14 15b.eat() // i am eat
点赞
收藏

评论区

加载中...

相关推荐

ES6的解构赋值是深拷贝or浅拷贝?

面试时候有面试官问到ES6的解构赋值是深拷贝还是浅拷贝?,这里做一个总结.ES6的解构赋值,大家应该都清楚,就是可以快速取出数组或者对象中的值;我们先来看一个使用案例:更多的解构赋值知识可以查看:https://es6.ruanyifeng.com/docs/destructuring那么,ES6的解构赋值到底是深拷贝还是浅拷贝呢?我们先来看一下深拷贝和浅

java 复制Map对象(深拷贝与浅拷贝)

java复制Map对象(深拷贝与浅拷贝)CreationTime2018年6月4日10点00分Author:Marydon1.深拷贝与浅拷贝  浅拷贝:只复制对象的引用,两个引用仍然指向同一个对象

java克隆之深拷贝与浅拷贝

版权声明:本文出自汪磊的博客,未经作者允许禁止转载。Java深拷贝与浅拷贝实际项目中用的不多,但是对于理解Java中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问的,所以理解深拷贝与浅拷贝是十分重要的。一、Java中创建对象的方式①:与构造方法有关

也谈JavaScript浅拷贝和深拷贝

网上关于这个话题,讨论有很多了,根据各路情况我自己整理了一下,最后还是能接近完美的实现深拷贝,欢迎大家讨论。javascript中的对象是引用类型,在复制对象的时候就要考虑是用浅拷贝还是用深拷贝。直接赋值对象是引用类型,如果直接赋值给另外一个对象,那么只是赋值一个引用,实际上两个变量指向的同一个数据对象,如果其中一个对象的属性变更,那么另外一个也会变更。示

Java对象拷贝原理剖析及最佳实践

作者:宁海翔1前言对象拷贝,是我们在开发过程中,绕不开的过程,既存在于Po、Dto、Do、Vo各个表现层数据的转换,也存在于系统交互如序列化、反序列化。Java对象拷贝分为深拷贝和浅拷贝,目前常用的属性拷贝工具,包括Apache的

python 赋值引用 浅拷贝 深拷贝

一、基础概念1、直接赋值:其实就是对象的引用(别名)。2、浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。3、深拷贝(deepcopy):copy模块的deepcopy方法,完全拷贝了父对象及其子对象。二、代码示例importcopya1,2,3,4,'a','b'原始对象ba

带你了解JS对象的浅拷贝和深拷贝 - HelloWorld