1. 应用 JSON 中的办法 JSON.parse(JSON.stringify(target)) // target 为要拷贝的对象
let obj1 = {
name:'xiaoming',
info:{address: 'beijing'}
}
let obj2 = JSON.parse(JSON.stringify(obj1))
2. 应用递归进行深拷贝
function deepClone(obj) {if (typeof obj === 'object' && target !== null) {let cloneObj = Array.isArray(obj) ? [] : {}
for (let key in obj) { // 遍历
if (typeof obj[key] === 'object') {cloneObj[key] = deepClone(obj[key]) // 是对象就再次调用该函数递归
} else {cloneObj[key] = obj[key] // 根本类型的话间接复制值
}
}
return cloneObj
} else {return target;}
}
上边两种曾经能够满足大部分利用场景,然而对于 Symbol 类型的数据和不可枚举属性以及 RegExp、Date、Error、Function 等援用类型无奈进行拷贝。
3. 改进版深拷贝
// 判断数据是否为一个援用类型对象,并且不为 null
const isComplexDataType = obj => (typeof obj === 'object' || typeof obj === 'function') && (obj !== null)
const deepClone = function(obj, hash = new WeakMap()) {if (obj.constructor === Date)
return new Date(obj) // 日期对象间接返回一个新的日期对象
if (obj.constructor === RegExp)
return new RegExp(obj) // 正则对象间接返回一个新的正则对象
// 如果循环援用了就用 weakMap 来解决,weakMap 为弱援用,会主动进行垃圾回收~~~~
if (hash.has(obj)) return hash.get(obj)
// 遍历所有键的特色,Object.getOwnPropertyDescriptors(obj) 返回的是一个对象,对象的属性名就是源对象的属性名,属性值就是该对象的形容对象(即拜访器属性或数据属性)let allDesc = Object.getOwnPropertyDescriptors(obj)
// 遍历传入参数所有键的个性
// 详见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors#%E6%B5%85%E6%8B%B7%E8%B4%9D%E4%B8%80%E4%B8%AA%E5%AF%B9%E8%B1%A1
let cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc)
// 继承原型链,这样下方进行遍历赋值的时候,也会将原型链中的数据也进行拷贝
hash.set(obj, cloneObj)
// Reflect.owmKeys(obj) 办法相似于 Object.keys(obj),然而后者会受 enumerable 影响,前者不会,应用这个办法能够将 Symbol 类型的数据也进行拷贝。// 详见 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect
for (let key of Reflect.ownKeys(obj)) {cloneObj[key] = (isComplexDataType(obj[key]) && typeof obj[key] !== 'function') ? deepClone(obj[key], hash) : obj[key]
}
return cloneObj
}