概念
浅拷贝:拷贝的只是对象的(引用)地址,新旧对象还是共享同一块内存,修改新对象会影响到原始对象数值发生变化
深拷贝:完全复制一个对象出来,新旧对象不共享内存,修改新对象不会改变原对象
浅拷贝
直接赋值
任何操作都会影响原数组
let arr = [1, 2, 3, 4]
let newArr = arr
newArr.push(5, 6, 7)
console.log('newArr:', newArr) // [1, 2, 3, 4, 5, 6, 7]
console.log('arr:', arr) // [1, 2, 3, 4, 5, 6, 7]
Object.assign()
拷贝属性值,假如属性值是一个对象的引用,那么也会指向那个引用
let obj = {
id: 1,
name: 'karim',
msg: {
age: 18
}
};
let newObj = {};
Object.assign(newObj, obj);
// 修改拷贝后的对象中某一个值后,原来的对象也会改变
newObj.msg.age = 20;
console.log('拷贝后新对象:', newObj.msg.age) // 拷贝后新对象: 20
console.log('原对象:', obj.msg.age) // 原对象: 20
Array.prototype.concat()
注意:如果数组中都是简单数据类型,可以作为深拷贝使用
let arr = [1, 2, 3, 4, 5]
let newArr = [].concat(...arr)
newArr.push(6)
console.log('newArr', newArr) // [1, 2, 3, 4, 5, 6]
console.log('arr', arr) // [1, 2, 3, 4, 5]
实现浅拷贝
let arr = [1, 2, 3, { obj: 'karim' }]
let newArr = [].concat(...arr)
console.log('newArr', newArr[3]) // {obj: "xiaoming"}
newArr[3].obj = 'xiaoming'
console.log('arr', arr[3]) // {obj: "xiaoming"}
Array.prototype.slice()
与
concat()
方法同理,简单类型可以作为深拷贝let arr = [1, 2, 3, 4, 5]
let newArr = arr.slice(0, 5)
console.log('newArr', newArr) // [1, 2, 3, 4, 5]
newArr.push(7)
console.log('arr', arr) // [1, 2, 3, 4, 5, 7]
实现浅拷贝
let arr = [{ a: '123' }, { b: '456' }]
let newArr = arr.slice(0, 2)
console.log('newArr', newArr) // 0: {a: "123"} 1: {b: "789"}
newArr[1].b = '789'
console.log('arr', arr) // 0: {a: "123"} 1: {b: "789"}
使用扩展运算符
let arr = [{ a: '123' }, { b: '456' }]
let newArr = [...arr]
newArr[0].a = '789'
console.log('newArr', newArr[0].a) // newArr 789
console.log('arr', arr[0].a) // arr 789
通过
for..in
循环进行对象的遍历```javascript let obj = { id: 1, name: ‘karim’, msg: {
age: 18
} };
let newObj = {}; for (let k in obj) { / console.log(‘对象的值为:’, obj[k])/ newObj[k] = obj[k]; } // 修改拷贝后的对象中某一个值后,原来的对象也会改变 newObj.msg.age = 20 console.log(‘拷贝后新对象:’, newObj.msg.age); // 拷贝后新对象: 20 console.log(‘原对象:’, obj.msg.age) // 原对象 20
实现浅拷贝的方式不仅局限于上面的几种还可以用jQuery中的`$.extend()`函数,`Lodash`工具库的`clone`方法,都可以实现,可以自行`To learn on their own`下。
<a name="510a44e6"></a>
## 深拷贝
<a name="Es0o6"></a>
### 手动复制对象
- 完全的`copy`一个新对象出来
```javascript
let obj = {
a: '123',
b: '234'
}
let newObj = {
a: obj.a,
b: obj.b
}
newObj.a = '456'
console.log('newObj', newObj)// {a: "456", b: "234"}
console.log('obj', obj) // {a: "123", b: "234"}
使用JSON.parse(JSON.stringify(obj))
用JSON.stringify把对象转成字符串,再用JSON.parse
把字符串转成新的对象,这个拷贝需要注意的是不能拷贝函数,因为JSON
格式字符串不支持Function
,在序列化的时候会自动删除
let obj = {
a: '123',
b: '234'
}
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj) // {a: "123", b: "234"}
newObj.a = '456'
console.log(obj) // {a: "123", b: "234"}
使用递归的方式
let obj = {
id: 1,
name: 'karim',
msg: {
age: 18
},
habits: ['reading', 'coding', 'playGames']
};
let newObj = {};
function deepCopy(newObj, obj) {
// 遍历对象
for (let k in obj) {
// 将属性值赋值到item变量中
let item = obj[k];
// 判断值是否是数组
if (item instanceof Array) {
newObj[k] = [];
deepCopy(newObj[k], item);
} else if (item instanceof Object) { // 判断是否是对象
newObj[k] = {};
deepCopy(newObj[k], item)
} else { // 是否是简单数据类型
newObj[k] = item;
}
}
// 返回深拷贝后的对象
return newObj
}
deepCopy(newObj, obj);
newObj.msg.age = 21;
console.log(newObj.msg.age); // 21
console.log(obj.msg.age); // 18
其他方法大家可以自行摸索下,比如lodash
的_.cloneDeep()
等等。
参考资料:
js深拷贝和浅拷贝及其实现方式:
深拷贝的实现方式
如何写出一个惊艳面试官的深拷贝?