浅拷贝
赋值表达式
const obj = {a:1}
const copy = obj
obj.a = 2
console.log(copy.a)// 2
Object.assign
const obj = { a: {b: '1'} };
const copy = Object.assign({}, obj);
copy.a.b = 2;
console.log(obj.a.b); // 2
- 当拷贝对象层级只有一层时,
Object.assign()是深拷贝
const obj = { a: 1 };
const copy = Object.assign({}, obj);
copy.a = 2;
console.log(obj.a); // 1
展开运算符(...)
- 同`Object.assign
concat
const arr = [1, {
a: 1
}]
const copy = arr.concat()
copy[0] = 2
copy[1].a = 2
console.log(arr); // [1, {a: 2}]
slice
- 同concat
- 原始值不受影响,引用值会受影响
深拷贝
JSON.parse(JSON.stringify(obj))
内部使用的是递归的方式,容易爆栈,同时做了循环引用的检测
const a = {}
a.a = a // 循环引用
JSON.parse(JSON.stringify(a))// Uncaught TypeError: Converting circular structure to JSON
递归实现
function myCopy(obj, weakMap = new WeakMap()) {
const typeofObj = typeof obj
if (typeofObj !== 'object' || typeofObj === null) {
return obj
}
if (obj instanceof Set) { // 处理Set类型
return new Set([...obj])
}
if (obj instanceof Map) { // 处理Map类型
return new Map([...obj])
}
// 每次拷贝对象前,都先看一下这个对象是不是已经拷贝过了,如果拷贝过了,就不需要拷贝了,直接用原来的,这样我们就能够保留引用关系了
// 防止循环引用
if (weakMap.has(obj)) {
return weakMap.get(obj)
}
const res = Array.isArray(obj) ? [] : {}
weakMap.set(obj, res)
const symbols = Object.getOwnPropertySymbols(obj)// 处理Symbol
const arr = Object.keys(obj).concat(symbols)
arr.forEach(key=>{
res[key] = myCopy(obj[key], weakMap)
})
return res
}
遍历栈实现
function myCopy2(obj, weakMap = new WeakMap()) {
const root = Array.isArray(obj) ? [] : {}
const stack = [{
data: obj,
parent: root
}]
while (stack.length) {
const { data, parent, key } = stack.pop()
var cur = parent
if (key) {
cur = parent[key] = Array.isArray(data) ? [] : {}
}
if (weakMap.has(data)) {
parent[key] = weakMap.get(data)
continue
}
weakMap.set(data, cur)
for (let k in data) {
const v = data[k]
if (typeof v === 'object') {
stack.push({
data: v,
key: k,
parent: cur
})
} else {
cur[k] = v
}
}
}
return root
}