# 深拷贝
对于对象的拷贝,存在浅拷贝和深拷贝的区别。
const obj = {
name: {
first: 'san',
last: 'zhang',
},
age: 20,
}
const arr = [{ first: 'san', last: 'zhang' }, 20]
# 浅拷贝
对于对象obj,浅拷贝只拷贝一级属性,如果属性值又是一个对象,则只会拷贝相应的引用。
# Object.assign
const obj1 = Object.assign({}, obj)
obj.name.first = 'si'
console.log(obj1.name.first) // si
const arr1 = Object.assign([], arr)
arr[0].first = 'si'
console.log(arr1[0].first) // si
# 扩展运算符
const obj1 = { ...obj }
obj.name.first = 'si'
console.log(obj1.name.first) // si
const arr1 = [...arr]
arr[0].first = 'si'
console.log(arr1[0].first) // si
# 数组切片
const arr1 = arr.slice()
arr[0].first = 'si'
console.log(arr1[0].first) // si
# 数组拼接
const arr1 = arr.slice()
arr[0].first = 'si'
console.log(arr1[0].first) // si
# 深拷贝
不同于浅拷贝,深拷贝会递归拷贝所有嵌套对象。
# JSON拷贝
const obj1 = JSON.parse(JSON.stringify(obj))
obj.name.first = 'si'
console.log(obj1.name.first) // san
const arr1 = JSON.parse(JSON.stringify(arr))
arr[0].first = 'si'
console.log(arr1[0].first) // san
JSON拷贝的问题: 不能拷贝方法、undefined和Symbol属性
const testObj = {
eat() {
console.log('eat')
},
[Symbol()]: 'test',
name: undefined,
}
const obj1 = JSON.parse(JSON.stringify(testObj))
console.log(obj1) // {}
# 递归遍历
function deepCopy(obj) {
// 判断是否为数组
const clone = Array.isArray(obj) ? [] : {}
// 判断是否为空对象
if (obj && typeof obj === 'object') {
for (let key in obj) {
// 拷贝自有属性
if (obj.hasOwnProperty(key)) {
// 属性值为对象则递归拷贝
if (obj[key] && typeof obj[key] === 'object') {
clone[key] = deepCopy(obj[key])
} else {
clone[key] = obj[key]
}
}
}
}
return clone
}
const obj1 = deepCopy(obj)
obj.name.first = 'si'
console.log(obj1.name.first) // san
const arr1 = deepCopy(arr)
arr[0].first = 'si'
console.log(arr1[0].first) // san
由于for in 不会遍历Symbol,这里的实现忽略了Symbol
const testObj = {
eat() {
console.log('eat')
},
[Symbol()]: 'test',
name: undefined,
}
const obj2 = deepCopy(testObj)
console.log(obj2) // { eat: [Function: eat], name: undefined }
# lodash.cloneDeep
const _ = require('lodash')
const obj1 = _.cloneDeep(obj)
obj.name.first = 'si'
console.log(obj1.name.first) // san
const arr1 = _.cloneDeep(arr)
arr[0].first = 'si'
console.log(arr1[0].first) // san
lodash.cloneDeep覆盖了所有可迭代属性
const testObj = {
eat() {
console.log('eat')
},
[Symbol()]: 'test',
name: undefined,
}
const obj3 = _.cloneDeep(testObj)
console.log(obj3) // { eat: [Function: eat], name: undefined, [Symbol()]: 'test' }