let obj = {
a: 1,
b: {
c: 2,
d: 3
},
d: new RegExp(/^\s+|\s$/g)
}
let obj1 = {
id: 1,
name: "张三",
gendar: 0,
workflow: [
{
id: 1,
name: '公司1',
date: '2024-01-01',
duty: []
}, {
id: 2,
name: '公司2',
date: '2024-02-01',
duty: [
{
id: 1,
dutyName: '公司2-职责1'
},
{
id: 2,
dutyName: '公司2-职责2'
}
]
}, {
id: 3,
name: '公司3',
date: '2024-04-01',
duty: [
{
id: 1,
dutyName: '公司3-职责1'
}
]
}
],
others: {
a: 1,
b: 2,
c: 3,
}
}
// 测试的obj对象
const objTest = {
// =========== 1.基础数据类型 ===========
num: 0, // number
num1: new Number(0),
str: '', // string
str1: new String(""),
bool: true, // boolean
bool1: new Boolean(true),
unf: undefined, // undefined
nul: null, // null
sym: Symbol('sym'), // symbol
// bign: BigInt(1n), // bigint
// =========== 2.Object类型 ===========
// 普通对象
obj: {
name: '我是一个对象',
id: 1
},
// 数组
arr: [0, 1, 2],
// 函数
func: function () {
console.log('我是一个函数')
},
// 日期
date: new Date(0),
// 正则
reg: new RegExp('/我是一个正则/ig'),
// Map
map: new Map().set('mapKey', 1),
// Set
set: new Set().add('set'),
// =========== 3.其他 ===========
[Symbol('1')]: 1 // Symbol作为key
};
// 4.添加不可枚举属性
Object.defineProperty(objTest, 'innumerable', {
enumerable: false,
value: '不可枚举属性'
});
// 5.设置原型对象
Object.setPrototypeOf(objTest, {
proto: 'proto'
})
// 6.设置loop成循环引用的属性
// objTest.loop = objTest
function deepClone(obj) {
// 这种可以应付大部分常规数据
if (typeof obj !== "object" || obj == null) return obj
const clone_obj = Array.isArray(obj) ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
clone_obj[key] = deepClone(obj[key])
}
}
return clone_obj
}
function deepClone1(obj, map = new WeakMap()) {
//使用 WeakMap 作为一个Hash表来进行查询 可以解决不能处理循环引用的问题
if (obj instanceof RegExp) return new RegExp(obj);
if (obj instanceof Date) return new Date(obj);
if (obj == null || typeof obj != "object") return obj
if (map.has(obj)) {
return map.get(obj)
}
let t = new obj.constructor()
map.set(obj, t)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
t[key] = deepClone1(obj[key], map)
}
}
return t
}
let clone_obj = deepClone1(objTest)
// obj.d = /^\s|[0-9]+$/g
objTest.str = "NMR"
// obj1.workflow[0].duty.push({ id: 1 })
console.log("拷贝对象:", clone_obj)
console.log("原对象:", objTest)
console.log(objTest === clone_obj)
console.log(objTest.func === clone_obj.func)
console.log(objTest.sym === clone_obj.sym)
console.log(objTest.innumerable ,clone_obj.innumerable)
console.log(clone_obj.proto)
function deepCloneTest(target) {
// WeakMap作为记录对象Hash表(用于防止循环引用)
const map = new WeakMap()
// 判断是否为object类型的辅助函数,减少重复代码
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)
}
// 处理函数对象
if (typeof data === 'function') {
return new Function('return ' + data.toString())()
}
// 如果该对象已存在,则直接返回该对象
const exist = map.get(data)
if (exist) {
return exist
}
// 处理Map对象
if (data instanceof Map) {
const result = new Map()
map.set(data, result)
data.forEach((val, key) => {
// 注意:map中的值为object的话也得深拷贝
if (isObject(val)) {
result.set(key, clone(val))
} else {
result.set(key, val)
}
})
return result
}
// 处理Set对象
if (data instanceof Set) {
const result = new Set()
map.set(data, result)
data.forEach(val => {
// 注意:set中的值为object的话也得深拷贝
if (isObject(val)) {
result.add(clone(val))
} else {
result.add(val)
}
})
return result
}
// 收集键名(考虑了以Symbol作为key以及不可枚举的属性)
const keys = Reflect.ownKeys(data)
// 利用 Object 的 getOwnPropertyDescriptors 方法可以获得对象的所有属性以及对应的属性描述
const allDesc = Object.getOwnPropertyDescriptors(data)
// 结合 Object 的 create 方法创建一个新对象,并继承传入原对象的原型链, 这里得到的result是对data的浅拷贝
const result = Object.create(Object.getPrototypeOf(data), allDesc)
// 新对象加入到map中,进行记录
map.set(data, result)
// Object.create()是浅拷贝,所以要判断并递归执行深拷贝
keys.forEach(key => {
const val = data[key]
if (isObject(val)) {
// 属性值为 对象类型 或 函数对象 的话也需要进行深拷贝
result[key] = clone(val)
} else {
result[key] = val
}
})
return result
}
return clone(target)
}
console