深浅拷贝
对象的引用赋值
js中一旦遇到引用数据类型,就会开辟一块堆内存,将引用数据类型的值进行储存,并给这块堆内存分配一个16进制地址。
1  | const info = {name:"forward",age:24};  | 

浅拷贝
- 浅拷贝:将第一层的数据数据完全拷贝过来,如果有引用类型,引用类型指向的是一个16进制地址,也会拷贝过来(即:拷贝的引用类型和原数据指向同一个内存地址)
 - (对象)如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址
 - (数组)如果数组元素(arr[index])是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化
 - 即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址
 - 常见的浅拷贝:
- Object.assign()
 - concat()
 - slice() 返回一个新的数组对象;原始数组不会被改变。
 - …拓展运算符
 - Lodash库 
_.clone(value) 
 
例如:
1  | //Object.assign()对象的浅拷贝  | 

将上述代码进行简单修改,加一个对象参数;这个对象参数会开辟一块堆内存(16进制地址);浅拷贝会将第一层的数据数据完全拷贝过来,引用类型指向的是一个16进制地址,也会拷贝过来(即:拷贝的引用类型指向同一个内存地址);
1  | //Object.assign()对象的浅拷贝  | 

Lodash JS库
Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库;用
_.clone(xxx)实现浅拷贝;详见:Lodash 中文文档
1  | const objects = [{ 'a': 1 }, { 'b': 2 }];  | 
数组的浅拷贝
1  | const arr = ['old', 1, true, null, undefined];  | 
深拷贝
- 深拷贝是指完全生成了一个新的对象,里面所有的东西都是新的,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
 
JSON.parse(JSON.string(xxx))
1  | const info = { name: "forward", age: 24,friend:{name:"zhangsan",age:23} };  | 
此方法缺点:JSON.stringify(..) 在对象中遇到 undefined 、 function 和 symbol 时会自动将其忽略, 在 数组中则会返回 null (以保证单元位置不变)。详见:JSON.stringify 深拷贝的弊端
1  | console.log(JSON.stringify(undefined));//undefined  | 
Lodash JS库
Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库;用
_.cloneDeep(xxx)实现深拷贝;详见:Lodash 中文文档
1  | const objects = [{ 'a': 1 }, { 'b': 2 }];  | 
浅拷贝+递归
见下文手写浅(深)拷贝
structuredClone()
在 JS 中深拷贝一个对象,我们一般会使用 lodash 的 deepClone 等方法。现在一个新的原生函数可以完美胜任这个任务:
structuredClone();这个函数几乎完美适配所有类型,甚至包括: Error,Date,Blob 等等。更棒的是而且现在主流的浏览器都兼容这个函数;
- 在哪里可以使用structuredClone()?
 
1  | const obj = {  | 
手写浅(深)拷贝
object.hasOwnProperty(propertyName)
- 用来检测属性是否为对象的私有属性,如果是,返回true,否则返回false; 参数propertyName指要检测的属性名;
 - 所以说不会检测原型链上的公有属性;
 - 说简单点,它能帮你指向你当前循环的对象,而过滤掉原型链上其它对象,因为在工作中我们很难保证其他人是否会修改原型链,这样做会更为保险;
 hasOwnProperty()方法会返回一个布尔值,指示对象自身属性中是否具有指定的属性(处理对象属性而不遍历原型链);Object.hasOwn()如果指定的对象自身有指定的属性,则静态方法Object.hasOwn()返回true。如果属性是继承的或者不存在,该方法返回false;备注:Object.hasOwn()旨在取代Object.hasOwnProperty()。
object.hasOwnProperty(propertyName)
1  | const object1 = {};  | 
Object.hasOwn()
1  | const object1 = {  | 
浅拷贝
遍历对象,然后把属性和属性值都放在一个新的对象不就好了~
1  | var shallowCopy = function(obj) {  | 
深拷贝
那如何实现一个深拷贝呢?说起来也好简单,我们在拷贝的时候判断一下属性值的类型,如果是对象,我们递归调用深拷贝函数不就好了~
1  | var deepCopy = function(obj) {  | 
总结
| 和原数据是否指向同一对象 | 第一层数据为基本数据类型 | 原数据中包含子对象 | |
|---|---|---|---|
| 赋值 | 是 | 改变会使原数据一同改变 | 改变会使原数据一同改变 | 
| 浅拷贝 | 否 | 改变不会使原数据一同改变 | 改变会使原数据一同改变 | 
| 深拷贝 | 否 | 改变不会使原数据一同改变 | 改变不会使原数据一同改变 |