深拷贝
将一个对象复制给另一个对象,复制出一个完全新的对象
Object.assign
拷贝对象,将源对象整合成新对象,当对象内也是对象时,复制引用地址
const cloneDeep = (value) => {
if (value === null || typeof value !== 'object') {
return value
}
const target = Array.isArray(value) ? [] : {}
for (const key in value) {
// 过滤掉原型上的属性
if (Object.hasOwnProperty.call(obj, key)) {
target[key] = cloneDeep(obj[key])
}
}
return target
}
export default cloneDeep
上述代码为什么要判断(Object.hasOwnProperty.call(obj, key)
由于对象 obj 的原型对象是 protoObj,所以在 for-in 循环中会遍历到 protoObj.b 属性,但这个属性并不是我们想要遍历的 obj 的自身属性。
因此加上 Object.hasOwnProperty.call(obj, key) 判断,可以确保只遍历到 obj 对象自身的可枚举属性,而不是遍历到其原型链上的属性。若 hasOwnProperty() 判断为 false,则表示该属性为原型链上的属性,需要跳过。
lodash中的深拷贝
- 确认是不是null或不是对象
- 通过map或wekMap来记录是否存在循环引用
- 复制对象
- 通过处理函数来复制对象
const cloneDeep = (value, customizer) => {
const uniqueSet = new WeakMap()
const deepClone = (object) => {
if (typeof customizer === 'function') {
const newValue = customizer(object)
if (newValue !== undefined) {
return newValue
}
}
if (object === null || typeof object !== 'object') {
return object
}
if (uniqueSet.has(object)) {
return uniqueSet.get(object)
}
const { constructor } = Object.getPrototypeOf(object)
const newObject = new constructor()
uniqueSet.set(object, newObject)
const keys = Object.keys(object)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const value = object[key]
newObject[key] = deepClone(value)
}
const symbols = Object.getOwnPropertySymbols(object)
for (let i = 0; i < symbols.length; i++) {
const symbol = symbols[i]
const value = object[symbol]
newObject[symbol] = deepClone(value)
}
return newObject
}
return deepClone(value)
}
export default cloneDeep