浅拷贝与深拷贝
浅拷贝
-
Object.assign()和Object.getPrototypeOf(),Object.getOwnPropertyDescriptors()Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj)) -
使用对象的展开语法
let cloneObj = { ...obj } -
对数组使用
concat、slice方法
深拷贝
-
通过
JSON.stringify转实现- 不能对
Date、Function、Symbol、Map、Set等类型进行拷贝 - 循环引用会出现问题
- 对不可枚举属性,对象的原型链等无法拷贝
JSON.parse(JSON.stringify()) - 不能对
-
手动实现深拷贝
- 使用
WeakMap处理循环引用 - 单独拷贝
Map,Set,Date,Function,RegExp等类型 - 使用 Reflect.ownKeys() 获取目标对象自身的属性
- 使用
Object.getOwnPropertyDescriptors获取对象的所有自身属性的描述符 和 Object.getPrototypeOf() 返回对象的原型,获取对象的浅拷贝(包括原型)
function deepClone(target) { // weakMap 防止循环引用 const map = new WeakMap() // obj function isObject(target) { return ( (typeof target === 'object' && target) || typeof target === 'function' ) } function clone(data) { // 基础类型 if (!isObject(data)) { return data } // 日期 正则对象 if ([Date, RegExp].includes(data.constructor)) { return new data.constructor(data) } // function if (typeof data === 'function') { return new Function('return ' + data.toString())() } // 对象已存在则直接返回 const exit = map.get(data) if (exit) { return exit } // Map if (data instanceof Map) { const result = new Map() data.forEach((key, value) => { if (isObject(value)) { result.set(key, clone(value)) } else { result.set(key, value) } }) map.set(data, result) return result } // Set if (data instanceof Set) { const result = new Set() data.forEach((value) => { if (isObject(value)) { result.add(clone(value)) } else { result.add(value) } }) map.set(data, result) return result } if (Array.isArray(data)) { const result = [] data.forEach((item) => { if (isObject(item)) { result.push(clone(item)) } else { result.push(item) } }) map.set(data, result) return result } // 收集键名 const keys = Reflect.ownKeys(data) const allDesc = Object.getOwnPropertyDescriptors(data) const result = Object.create(Object.getPrototypeOf(data, allDesc)) keys.forEach((key) => { const value = data[key] if (isObject(value)) { result[key] = clone(value) } else { result[key] = value } }) map.set(data, result) return result } return clone(target) } - 使用