概念
浅拷贝: 浅拷贝指的是将一个对象的属性值复制到另一个对象,如果属性值是引用类型的话,那么会将这个引用的地址复制给新对象。因此两个对象会有同一个引用类型的引用。浅拷贝可以用Object.assign()和扩展运算符来实现。
深拷贝: 深拷贝相对于浅拷贝而言,如果遇到属性值为引用类型的时候,它新建一个引用类型并将对应的值赋给它,因此对象获得一个新的引用类型而不是一个原有类型的引用。
实现
浅拷贝
浅拷贝一般有以下几种实现方法:
- Object.assign()
- 扩展运算符
- 手写实现
Object.assign
Object.assign是ES6中对象的拷贝方法,其用法详见MDN。
const obj = {
name: 'zhangsan',
b: {
bb: 123
}
}
const newObj = Object.assign({}, obj)
// 引用类型修改之后,newObj也会修改
obj.b.bb = 234
// newObj不会变
obj.name = 'lisi'
console.log(obj, newObj);
注意,如果原数据(obj)只有一层(基本数据类型)时,就是深拷贝。所以当修改obj的name属性时,newObj中的name不会变。
扩展运算符
ES2018把扩展运算符...
引入到了对象。
const obj = {
name: 'zhangsan',
b: {
bb: 123
}
}
const newObj = {...obj}
// 引用类型修改之后,newObj也会修改
obj.b.bb = 234
// newObj不会变
obj.name = 'lisi'
console.log(obj, newObj);
注意,同上Object.assign,当只有一层数据时是深拷贝。
自己实现浅拷贝
const obj = {
name: 'zhangsan',
b: {
bb: 123
}
}
function shallowCopy(o) {
if (!o || typeof o !== "object") {
return
}
let res = Array.isArray(o) ? [] : {}
for (let key in o) {
if (o.hasOwnProperty(key)) {
res[key] = o[key]
}
}
return res
}
const newObj = shallowCopy(obj)
obj.name = 'lisi'
obj.b.bb = '234'
console.log(obj, newObj);
深拷贝
深拷贝一般有以下几种实现方法:
- JSON.parse(JSON.stringify(obj))
- lodash的_.cloneDeep
- 手写实现深拷贝
JSON.parse(JSON.stringify(obj))
常用方法之一,原理是先用JSON.stringify()把js对象序列化成json字符串,再用JSON.parse()来反序列化json字符串成js对象。这个方法简单粗暴,但是当对象中有函数、undefined、symbol时,JSON.stringify后都会消失。
const obj = {
name: 'zhangsan',
b: {
bb: 123
}
}
const newObj = JSON.parse(JSON.stringify(obj))
obj.name = 'lisi'
obj.b.bb = 234
console.log(obj, newObj);
lodash的_cloneDeep
手动实现深拷贝
const obj = {
name: 'zhangsan',
b: {
bb: 123
}
}
function cloneDeep(o) {
if (!o || typeof o !== "object") {
return
}
const res = Array.isArray(o) ? [] : {}
for (let key in o) {
if (o.hasOwnProperty(key)) {
if (typeof o[key] === "object") {
res[key] = cloneDeep(o[key])
} else {
res[key] = o[key]
}
}
}
return res
}
const newObj = cloneDeep(obj)
obj.name = 'lisi'
obj.b.bb = 234
console.log(obj, newObj);