1、常见的一种实现方式
const info = JSON.parse(JSON.stringify(obj))
2、简单实现 deepClone
//工具函数
function isObject(value) {
const type = typeof value
return (value !== null) && (type === 'object' || type === 'function')
}
function deepClone(originValue) {
//1.判断传入的originValue是不是一个对象类型
if (!isObject(originValue)) return originValue
//2.简单实现
const newObj = {}
for (const key in originValue) {
newObj[key] = deepClone(originValue[key])
}
return newObj
}
//测试一下
const obj = {
name: '当地小有名气可爱鬼',
height: 170,
eat: {
first: '臭豆腐',
second: '榴莲'
}
}
const test = deepClone(obj)
console.log(test === obj); //false
obj.eat.first = '螺蛳粉'
console.log(test); //{ name: '当地小有名气可爱鬼', height: 170, eat: { first: '臭豆腐', second: '榴莲' } }
3、增加功能 - 处理其他数据类型
//工具函数
function isObject(value) {
const type = typeof value
return (value !== null) && (type === 'object' || type === 'function')
}
function deepClone(originValue) {
//类型判断
// 判断是否是一个Set类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
// 判断是否是一个Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description)
}
// 判断如果是函数类型, 那么直接使用同一个函数
if (typeof originValue === 'function') {
return originValue
}
//判断传入的originValue是不是一个对象类型
if (!isObject(originValue)) return originValue
//判断传入的对象是数组,还是对象
const newObject = Array.isArray(originValue) ? [] : {}
for (const key in originValue) {
newObject[key] = deepClone(originValue[key])
}
//处理一下symbol的key
const symbolKeys = Object.getOwnPropertySymbols(originValue)
for (const iterator of symbolKeys) {
newObject[iterator] = deepClone(originValue[iterator])
}
return newObject
}
//测试一下
let s1 = Symbol('s1')
let s2 = Symbol('s2')
const info = {
name: '当地小有名气可爱鬼',
height: 170,
eat: {
first: '臭豆腐',
second: '榴莲'
},
singer: ['周杰伦', '孙燕姿', '邓紫棋'],
//symbol 可以做key\value
[s1]: '我是s1',
s2: s2,
bar: function () {
return '我是函数'
},
set: new Set(['1', '2', '3']),
map: new Map([
['a', 'b'],
['c', 'd']
])
}
const check = deepClone(info)
console.log(check === info); //false
info.eat.first = '小龙虾'
console.log(info, '我是info');
// {
// name: '当地小有名气可爱鬼',
// height: 170,
// eat: {
// first: '小龙虾',
// second: '榴莲'
// },
// singer: ['周杰伦', '孙燕姿', '邓紫棋'],
// s2: Symbol(s2),
// bar: [Function: bar],
// set: Set(3) {
// '1',
// '2',
// '3'
// },
// map: Map(2) {
// 'a' => 'b', 'c' => 'd'
// },
// [Symbol(s1)]: '我是s1'
// }
// 我是info
console.log(check, '我是check');
// {
// name: '当地小有名气可爱鬼',
// height: 170,
// eat: {
// first: '臭豆腐',
// second: '榴莲'
// },
// singer: ['周杰伦', '孙燕姿', '邓紫棋'],
// s2: Symbol(s2),
// bar: [Function: bar],
// set: Set(3) {
// '1',
// '2',
// '3'
// },
// map: Map(2) {
// 'a' => 'b', 'c' => 'd'
// },
// [Symbol(s1)]: '我是s1'
// }
// 我是check
console.log(check.s1 === info.s1);//true
console.log(check.s2 === info.s2);//false
4、增加功能 - 解决循环引用的问题(WeakMap)
function isObject(value) {
const type = typeof value
return (value !== null) && (type === 'object' || type === 'function')
}
function deepClone(originValue , map = new WeakMap()) {
//类型判断
// 判断是否是一个Set类型
if (originValue instanceof Set) {
return new Set([...originValue])
}
// 判断是否是一个Map类型
if (originValue instanceof Map) {
return new Map([...originValue])
}
// 判断如果是Symbol的value, 那么创建一个新的Symbol
if (typeof originValue === "symbol") {
return Symbol(originValue.description)
}
// 判断如果是函数类型, 那么直接使用同一个函数
if (typeof originValue === 'function') {
return originValue
}
//判断传入的originValue是不是一个对象类型
if (!isObject(originValue)) return originValue
//处理数据循环引用的问题
if (map.has(originValue)) {
return map.get(originValue)
}
//判断传入的对象是数组,还是对象
const newObject = Array.isArray(originValue) ? [] : {}
map.set(originValue, newObject)
for (const key in originValue) {
newObject[key] = deepClone(originValue[key],map)
}
//处理一下symbol的key
const symbolKeys = Object.getOwnPropertySymbols(originValue)
console.log(symbolKeys, 'symbolKeys');
for (const iterator of symbolKeys) {
newObject[iterator] = deepClone(originValue[iterator],map)
}
return newObject
}
//测试一下:
let s1 = Symbol('s1')
let s2 = Symbol('s2')
const info = {
name: '当地小有名气可爱鬼',
height: 170,
eat: {
first: '臭豆腐',
second: '榴莲'
},
singer: ['周杰伦', '孙燕姿', '邓紫棋'],
//symbol 可以做key\value
[s1]: '我是s1',
s2: s2,
bar: function () {
return '我是函数'
},
set: new Set(['1', '2', '3']),
map: new Map([
['a', 'b'],
['c', 'd']
])
}
info.list = info //设置一个引用,如果不做处理会报栈溢出: Maximum call stack size exceeded
const check = deepClone(info)
console.log(check === info); //false
info.eat.first = '小龙虾'
console.log(info);
console.log(check.s2 === info.s2)
简单拓展一下这里为什么使用weakMap:
1.Map可以使用任意类型的key值,不限字符串,对象等
2.WeakMap只能使用对象作为key值,是弱引用,当从WeakMap中移除时,会自动垃圾回收