深浅拷贝
浅拷贝
手写
遍历对象,把属性及属性值都放在一个新的对象。
function shallowCopy(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return
// 根据 obj 的类型判断是新建一个数组还是对象
let newObj = Array.isArray(obj) ? [] : {}
// 遍历 obj,并且判断是 obj 的属性才拷贝
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key]
}
}
return newObj
}
扩展运算符
let obj1 = {
a: 1,
b: {
val: 2
}
}
let obj2 = {...obj1}
obj1.a = 3
obj1.b.val = 4
console.log(obj1) // { a: 3, { b: { val: 4 } } }
console.log(obj2) // { a: 1, { b: { val: 4 } } }
Object.assign
let obj1 = {
a: 1,
b: {
val: 2
}
}
let obj2 = Object.assign({}, obj1)
obj1.a = 3
obj1.b.val = 4
console.log(obj1) // { a: 3, { b: { val: 4 } } }
console.log(obj2) // { a: 1, { b: { val: 4 } } }
Array.prototype.slice
let arr1 = [1, { val: 2 }]
let arr2 = arr1.slice()
arr1[0] = 3
arr1[1].val = 4
console.log(arr1) // [3, { val: 4 }]
console.log(arr2) // [1, { val: 4 }]
Array.prototype.concat
let arr1 = [1, { val: 2 }]
let arr2 = arr1.concat()
arr1[0] = 3
arr1[1].val = 4
console.log(arr1) // [3, { val: 4 }]
console.log(arr2) // [1, { val: 4 }]
深拷贝
手写
遍历对象,把属性及属性值放在一个新的对象。当属性值是对象时,递归调用深拷贝函数。
var deepCopy = function(obj) {
// 只拷贝对象
if (typeof obj !== 'object') return
// 根据 obj 的类型判断是新建一个数组还是对象
var newObj = Array.isArray(obj) ? [] : {}
// 遍历 obj,并且判断是 obj 的属性才拷贝。属性值是对象时,采用递归。
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]
}
}
return newObj
}
WARNING
该方法虽实现了深拷贝,但也存在一些问题。
- 无法解决循环引用
- 无法拷贝
symbol和不可枚举的属性 - 无法拷贝特殊类型的值,如
Date、RegExp等
更完善的手写方法,待后续有空时再研究补上。
JSON.parse(JSON.stringify(obj))
let obj1 = {
a: 1,
b: {
val: 2
}
}
let obj2 = JSON.parse(JSON.stringify(obj1))
obj1.a = 3
obj1.b.val = 4
console.log(obj1) // { a: 3, { b: { val: 4 } } }
console.log(obj2) // { a: 1, { b: { val: 2 } } }
WARNING
该方法虽简单粗暴,但也存在一些问题。
- 无法解决循环引用
- 无法拷贝对象的原型链
- 无法拷贝不可枚举的属性
- 拷贝
Date引用类型会变成字符串 - 拷贝
RegExp引用类型会变成空对象 - 拷贝
NaN、±Infinity会变成null - 拷贝
undefined、symbol、function会消失
lodash.cloneDeep
let obj1 = {
a: 1,
b: {
val: 2
}
}
let obj2 = _.cloneDeep(obj1)
obj1.a = 3
obj1.b.val = 4
console.log(obj1) // { a: 3, { b: { val: 4 } } }
console.log(obj2) // { a: 1, { b: { val: 2 } } }