数组和对象的深拷贝
浅克隆:只克隆第一级,对于后代级别还是公用之前的
1.新客隆的obj2的某些操作还是可以改变obj1中的内容的
对象的克隆
let obj1={
name:'xxx',
course:{
c1:'语文',
c2:'数学'
}
};
console.log(obj1)
let obj2 = obj1
- 克隆1:循环遍历(浅克隆)
let obj2={}
keys = [...Object.keys(obj1),
...Object.getOwnPropertySymbols(obj1)
]
keys.forEach(key=>{
obj2[keys]=obj1[keys]
})
console.log(obj2)
- 克隆2:基于展开运算符(浅克隆)
let obj2 = {...obj1}
console.log(obj2===obj1)
console.log(obj2.course===obj1.cours)
- 克隆3:基于Object.assign([obj1],[obj2])(浅克隆);返回的结果依然是obj1堆内存,只不过是把obj2中的键值对和原始obj1的键值对合并在一起
let obj2 = Object.assign(obj1,{})//obj2===obj1->true
let obj2 = Object.assign({},obj1)//obj2===obj1->false
cons ole.log(obj2.course===obj1.cours)
数组的克隆
let arr1 = [10,20,[30,40]]
- 克隆1:循环foreach/map(浅克隆)
let arr2 = []
arr1.forEach((item,index)=>{
arr2[index] = item
})
arr2=arr1.map(item=>item)
console.log(arr2 === arr1)
consoel.log(arr2[2] === arr1[2])
- 克隆2:基于展开运算符或者Object.assign(浅克隆)
- 克隆3:基于slice、concat...这些可以实现
let arr2 = arr1.slice()
深克隆:当前级及其所有的后代级别,最后都会克隆一份一摸一样的,和原始数据结构不存在任何关联
let obj1={
name:'xxx',
course:{
c1:'语文',
c2:'数学'
}
};
let arr1 = [10,20,[30,40]]
- 深克隆1:JSON.stringify/JSON.parse
- 基于stringify,把原始的对象(或者数组)变成一个字符串
- 再基于parse,把字符串转换为对象,此时对象对应的每个级的堆内存,都是全新开辟的
- 存在的问题:JSON.stringify变为字符串,很多类型不支持
- 正则、Math对象会被处理为空对象
- 具备函数、symbol属性值的属性直接被干掉了
- bigint处理不了,会报错
- 日期对象最后还是字符串
- ...
let obj2 = JSON.parse(JSON.stringify(obj1))
let arr2 = JSON.parse(JSON.stringify(arr1))
console.log(obj2===obj1)
console.log(obj2.course===obj1.cours)
console.log(arr2 === arr1)//false
consoel.log(arr2[2] === arr1[2])//false
浅克隆
(function () {
var getProto = Object.getPrototypeOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;
var ObjectFunctionString = fnToString.call(Object);
[
"Boolean",
"Number",
"String",
"Symbol",
"Function",
"Array",
"Date",
"RegExp",
"Object",
"Error"
].forEach(function (name) {
class2type["[object " + name + "]"] = name.toLowerCase();
});
function toType(obj) {
if (obj == null) {
return obj + "";
}
return typeof obj === "object" || typeof obj === "function" ?
class2type[toString.call(obj)] || "object" :
typeof obj;
}
window.toType = toType;
})();
function getOwnPropertys(obj){
if(obj == null) return[];
return [
...Object.keys(obj),
...Object.getOwnPropertySymbol(obj)
]
}
function shallowClone(obj){
let type = toType(obj);
if(/^(number|string|boolean|null|undefined/symbol|bigint)$/.test(type)) return obj;
if(/^(function)$/.test(type)) {
return function proxy(){
return obj();
};
}
if(/^(object|date)$/.test(type)) {
return new obj.constructor(obj);
if(/^error$/.test(type)) {
return new Error(obj.message);
}
let keys = getOwnPropertys(obj),
clone = {};
Array.isArray(obj)?clone=[]:null;
keys.forEach(key=>{
clone[key]=obj[key]
})
<!-- for(let i =0;j<keys.length;i++){
let key = keys[i];
clone[key]=obj[key];
} -->
return clone
}
深克隆
function deepclone(obj,cache=new Set()){
//只有数组和对象我们再处理深克隆,其余情况 直接按照浅克隆处理
let type = toType(obj)
if(!/^(object|array)$/.test(type)) return shallowClone(obj)
//避免自己嵌套自己
if(cache.has(obj)) return shallowclone(obj)
cache.add(obj)
let keys = getOwnPropertys(obj),
clone = {}
type === "array"?clone =[]:null
keys.forEach(key=>{
clone[key]=deepclone(obj[key],cache)
})
return clone
}