一、浅拷贝
浅拷贝只能解决一层的拷贝,属性值为引用地址时则复制的是引用地址
1、浅拷贝:Object.assign()
合并对象,后面参数的属性会覆盖前面同名属性
var obj = {a:[1,2,3],b:'b'};
var test = Object.assign({},obj);obj.a.push("123");console.log(test);
//{a:[1,2,3,'123'],b: "b"}
注意:参数为数组时,会把数组当成对象来处理 Object.assign([1,2,3],[45]);//[4,5,3]
2、...解构赋值进行浅拷贝
var obj={a:'a',b:'b'}; var result = {...obj}; result.a;//a
3、数组浅拷贝
对于值都是普通数据类型的数组,可以使用数组的 slice 或者 concat 函数来进行深拷贝。 var a = [1,2,3]; var b = a.slice(0); var c = [].concat(a);console.log(c);
二、深拷贝
1、使用JSON序列化函数进行深拷贝
JSON.parse(JSON.stringify(obj))
- 会忽略值为undefined、Symbol、函数的键值对,不能序列化函数,不能解决循环引用的对象
- 数组中的空位和数组中的undefined会转换成null
- 值为new Data(),会转换成时间字符串
循环引用报错
let obj = {
a: 1,
b: {}
}
obj.b.c = obj.b
let result = JSON.parse(JSON.stringify(obj))
console.log(result)
忽略undefined、symbol、函数
var objtest= {
a:undefined,
b:Symbol('sym'),
c:function(){},
d:"test"};
var result = JSON.parse(JSON.stringify(objtest));
console.log(result);
//{d:"test"}
解决深拷贝以上问题:
<script>
const isObject = obj => {
return typeof obj === "object" && obj != null
}
const cloneDeep = (obj, hash = new WeakMap()) => {
if (!isObject(obj)) {
return obj
}
if (hash.has(obj)) { // 解决循环引用引发的问题
return hash.get(obj)
}
const type = [Date, RegExp, Set, Map, WeakMap, WeakSet]
if (type.includes(obj.constructor)) {
return new obj.constructor(obj)
}
const allDesc = Object.getOwnPropertyDescriptors(obj) // 遍历传入参数所有键的特性
//Object.getPrototypeOf(obj)新创建对象的原型对象
//allDesc传入对象的自有可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)将为新创建的对象添加指定的属性值和对应的属性描述符。
const cloneObj = Object.create(Object.getPrototypeOf(obj), allDesc) // 继承原型
hash.set(obj, cloneObj)
//**Reflect.ownKeys(target)**是返回所有的属性key,包括不可枚举类型,不包括继承的属性
for (let key of Reflect.ownKeys(obj)) {
// Reflect.ownKeys(obj)可以拷贝不可枚举属性和Symbol类型
// 注意:writable 为 false 的属性会赋值失败,因此 writable 为 false 的属性是浅拷贝
cloneObj[key] = isObject(obj[key]) ? cloneDeep(obj[key], hash) : obj[key]
}
return cloneObj
}
// 测试
let obj = {
bigInt: BigInt(1111111111),
set: new Set([2]),
map: new Map([
["a", 33],
["b", 44]
]),
num: 0,
str: "",
boolean: true,
unf: undefined,
nul: null,
innerObj: {
name: "我是一个对象",
id: 1
},
arr: [0, 1, 2],
func: function () {
console.log("函数")
},
date: new Date(0),
reg: new RegExp("/正则/ig"),
[Symbol("1")]: 1,
loopA:{a:'a'},
innerObj:{a:'a',b:'b',c:'c',d:'d'}
}
obj.loopA.b = obj.loopA;
let cloneObj = cloneDeep(obj)
console.log("obj", obj)
console.log("cloneObj", cloneObj)
</script>