什么是深拷贝/深复制?什么是浅拷贝/浅复制?本文将针对深浅拷贝这道常见面试题呈现深浅拷贝的理解,以及深浅拷贝的方法归类。将呈现多种深浅拷贝的方法,包括手写递归深拷贝!

什么是浅拷贝:
浅拷贝(Shallow copy)顾名思义,就是浅层次的拷贝,有多浅呢?浅到只能拷贝一层。浅拷贝是指将某个对象拷贝/复制成一个新的对象,使新的对象具有和被拷贝的对象相同的属性、属性值和方法。但是这种拷贝只拷贝第一层,因为无论是对象还是数组,都能在里面再嵌套数组和对象,都能无限嵌套。而对象/数组都是属于引用数据类型,堆中存储的是引用地址,栈中才存储的是对应数据。
以上描述可能晦涩难懂,更简单的描述如下:
浅拷贝只拷贝对象或者数组的第一层数据,基本数据类型拷贝属性和属性值,引用数据类型拷贝引用地址
因为浅拷贝无法拷贝嵌套的数组或者对象,因此深拷贝应运而出,将由深拷贝解决这个问题!
下面是大C老师的回答:

浅拷贝的方法:
对象浅拷贝有两种常用的方法:
扩展运算符(展开运算符)
const originalObj = { name: "John", age: 25 };
const shallowCopyObj = { ...originalObj };Object.assign()
const originalObj = { name: "John", age: 25 };
const shallowCopyObj = Object.assign({}, originalObj);数组常用的浅拷贝方法:
扩展运算符(展开运算符)
const originalObj = { name: "John", age: 25 };
const shallowCopyObj = { ...originalObj };//和这对象的的浅拷贝方法一致Array.from()方法
const originalArray = [1, 2, 3]; const shallowCopyArray = Array.from(originalArray);
Array.prototype.slice()方法
const originalArray = [1, 2, 3]; const shallowCopyArray = originalArray.slice();
Array.concat()方法
const newArray = array1.concat(array2, array3, ..., arrayN);
什么是深拷贝:
深拷贝(Deep copy)简单的说是将对象全部拷贝,如果有嵌套,则每层都拷贝,并非只拷贝地址,而是拷贝完整的数据,使两个对象之间无论嵌套了多少层对象,都不会互相干扰!
深拷贝:
在堆内存中开辟一个空间,创建一个新对象
递归的拷贝原对象的所有属性和方法,拷贝前后两个对象,相互不影响
下面是大C老师的原话:

深拷贝的方法:
一般来说,深拷贝有三种常用的方式:
1、手写递归深拷贝
这个将放到下面去详解,因为代码量比较多!
2、序列化搭配反序列化
这个就是使用JSON.stringify()和JSON.parse()方法,但是这样也会有一定的缺陷
缺陷:
①拷贝对象的属性值,如果是(function/undefined)/ symbol,这个键值对丢失
②如果深拷贝对象的属性值是RegExp,会变成空对象{}
③如果是NaN,Infinity,属性值会变成null
④如果拷贝日期对象,会变成日期字符串
3、第三方lodash插件库的深拷贝
// 引入js
<script src="./js/lodash.min.js"></script>
const obj = {
name: 'zjl',
age: 18,
hobby:['dance','music'],
book:{
book_name:'宗波尘客',
price:66
},
test0:function(){},
test1:undefined,
test2:Symbol('id'),
test3:new RegExp(/abc/, 'i'),
test4:NaN,
test5:Infinity,
test6:new Date()
}
// 深拷贝 _是lodash的一个对象,里面有一个方法 cloneDeep()
const o = _.cloneDeep(obj)
console.log(o)手写递归深拷贝详解:
将用有一定区别的几种手写递归深拷贝的方式用代码呈现给大家,大家根据自己最容易看懂的去理解,然后能手写出来即可!
代码1:
const obj = {
name: 'zjl',
age: 18,
hobby:['dance','music'],
book:{
book_name:'Golang',
price:66
}
}
// 递归实现深拷
function deepClone(obj){
// 1. 如果是基本数据类型,直接返回
if (typeof obj !== 'object') return obj
// 2. 判断传入的是数组还是对象,在内存中新创建数组/对象
let newObj = Array.isArray(obj)? [] : {}
// 给新创建的对象添加属性和值,遍历传入过来的那个对象的属性,一个一个添加到新对象上
return newObj
}
const res = deepClone()
console.log(res)代码2:
const obj = {
name: 'zjl',
age: 18,
hobby:['dance','music'],
book:{
book_name:'Golang',
price:66
}
}
// 深拷贝,在内存中开辟一个空间,创建一个新的对象, ===> 考虑数组和对象两种情况
// 递归实现深拷
function deepClone(obj){
// 1. 如果是基本数据类型,直接返回
if (typeof obj !== 'object') return obj
// 2. 判断传入的是数组还是对象,在内存中新创建数组/对象
let newObj = Array.isArray(obj) ? [] : {}
// 给新创建的对象添加属性和值,遍历传入过来的那个对象的属性,一个一个添加到新对象上
for(let key in obj){
if (typeof obj[key] === 'object'){
// 当key 取 hobby时, obj[key] 是 ['dance','music'] 把它传入到deepClone再拷贝
newObj[key] = deepClone(obj[key])
} else {
newObj[key] = obj[key]
}
}
return newObj
}
const res = deepClone(obj)
console.log(res)
res.hobby[0] = 'rapper'
console.log(obj)代码3:
function deepCopy(obj) {
if (typeof obj !== "object" || obj === null) {
return obj; // 基本数据类型和 null 直接返回
}
var clone = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (Object.prototype.hasOwnProperty.call(obj, key)) {
clone[key] = deepCopy(obj[key]); // 递归复制每个属性的值
}
}
return clone;
}
// 示例对象
var originalObj = {
name: "John",
age: 25,
hobbies: ["reading", "running"],
address: {
street: "123 Main St",
city: "New York"
}
};
// 深拷贝对象
var deepCopyObj = deepCopy(originalObj);
// 修改深拷贝对象的属性
deepCopyObj.name = "Jane";
deepCopyObj.hobbies.push("painting");
deepCopyObj.address.city = "Los Angeles";
console.log(originalObj.name); // 输出: "John"
console.log(originalObj.hobbies); // 输出: ["reading", "running"]
console.log(originalObj.address.city); // 输出: "New York"代码4:

关于深浅拷贝提示:
这是一道常见面试题,一般面试官会询问什么是深浅拷贝,深浅拷贝的区别,以及可能会让你手写深浅拷贝。本文仅包含常用的深浅拷贝方法,如需要更多方法,可咨询大C老师哦!