浅克隆
- 只克隆了第一级,对于后代级别还是公用之前的
- 操作新克隆的对象中的某些仍然可以改变原对象中的内容
1.循环遍历
对象
let obj = {
name:'牧鱼',
age:26,
other:{
job:'前端',
city:'杭州'
}
}
let clone ={},
keys = [
...Object.keys(obj),
...Object.getOwnPropertySymbols(obj)
]
keys.forEach((item)=>{
clone[item] = obj[item]
})
console.log(obj===clone)
console.log(obj.other===clone.other)
数组
let arr = [1,2,3,[4,5]]
let clone = []
arr.forEach((item,index)=>{
clone[index] = item
})
clone = arr.map(item => item)
console.log(arr===clone)
console.log(arr[3]===clone[3])
2.展开运算符
对象
let obj = {
name:'牧鱼',
age:26,
other:{
job:'前端',
city:'杭州'
}
}
let clone ={...obj};
console.log(obj===clone)
console.log(obj.other===clone.other)
数组
let arr = [1,2,3,[4,5]]
let clone = [...arr]
console.log(arr===clone)
console.log(arr[3]===clone[3])
3.Object.assign
对象
let obj = {
name:'牧鱼',
age:26,
other:{
job:'前端',
city:'杭州'
}
}
let clone = Object.assign({},obj);
console.log(obj===clone)
console.log(obj.other===clone.other)
数组
let arr = [1,2,3,[4,5]]
let clone = Object.assign([],arr)
console.log(arr===clone)
console.log(arr[3]===clone[3])
4.slice/concat(数组)
let arr = [1,2,3,[4,5]]
let clone = arr.slice()
let clone = arr.concat([])
console.log(arr===clone)
console.log(arr[3]===clone[3])
深克隆
- 当前级及其所有后代级别,都会克隆一份一模一样的,和原始的数据结构不存在任何关联
- 消耗内存空间
1.JSON.parse(JSON.stringify(对象/数组))
- 基于JSON.stringify,把原始的对象/数组转换为字符串
- 再基于JSON.parse,把字符串转化为对象,此时对象中所有级别的堆内存都是全新开辟的
- JSON.stringify转化为字符串时,对很多类型不支持
- 不支持1:正则对象/Math对象会被处理为空对象
- 不支持2:值为函数/Symbol/undrfined的属性会被删除
- 不支持3:bigInt无法处理,报错:Uncaught TypeError: Do not know how to serialize a BigInt
- 不支持4:日期对象处理完成后,还是字符串
let obj = {
name:'牧鱼',
age:26,
other:{
job:'前端',
city:'杭州'
},
reg:/^牧鱼$/g,
math:Math,
fn:function(){},
sym:Symbol(1),
un:undefined,
big:10n,
date:new Date()
}
let clone = JSON.parse(JSON.stringify(obj));
console.log(obj===clone)
console.log(obj.other===clone.other)
console.log(clone.reg)
console.log(clone.math)
console.log(clone.fn)
console.log(clone.sym)
console.log(clone.un)
console.log(clone.big)
console.log(clone.date)
自定义方法实现浅克隆与深克隆
function getOwnProperty(obj){
if(obj == null) return [];
return [
...Object.keys(obj),
...Object.getOwnPropertySymbols(obj)
]
}
function shallowClone(obj){
let type = typeof obj;
let toString = Object.prototype.toString;
if (obj==null) return obj;
if(type!=="function"&&type!=="object") return obj;
if(type==="function"){
return function proxy(){
return obj()
}
}
if(/(Date|RegExp)/.test(toString.call(obj))) return new obj.constructor(obj);
if(/Error/.test(toString.call(obj))) return new obj.constructor(obj.message);
let keys = getOwnProperty(obj),
clone ={};
Array.isArray(obj) ? clone = [] : null;
keys.forEach((key)=>{
clone[key] = obj[key]
})
return clone
}
function deepClone(obj,cache = new Set()){
let toString = Object.prototype.toString;
if(!/(Object|Array)/.test(toString.call(obj))) return shallowClone(obj);
if(cache.has(obj)) return shallowClone(obj);
cache.add(obj);
let keys = getOwnProperty(obj),
clone = {};
/Array/.test(toString.call(obj))?clone = []:null;
keys.forEach((key)=>{
clone[key] = deepClone(obj[key],cache)
})
return clone
}