JavaScript中对象只是对内存地址的一个引用.创建引用的副本会导致2个引用指向同一个内存地址
let obj1 = {a:1} let obj2 = obj1; obj1和obj2指向的都是同一个内存地址,任何一个改变a值 ,另一个也会改变
1.浅拷贝(只适用对象简单,只有值类型属性)
一.扩展运算符 ... (可以将多个源对象拷贝到目标对象)
let obj1 = {a:1}; let obj2 = {b:2}; let obj3 = {...obj1, ...boj2}; // obj3 = {a:1, b:2}
二.Object.assign({},obj1,obj2)
let obj1 = {a:1}; let obj2 = {b:2}; let obj3 = Object.assign({},obj1,obj2); // obj3 = {a:1, b:2}
2.深拷贝
一. JSON.parse(JSON.stringify(obj)) 将对象序列化成Json字符串,再反序列化为Json对象,存在一些缺点
1).obj里有时间对象Date, 拷贝的会变成时间字符串
2).obj里有RegExp、Error对象,则序列化的结果将只得到空对象
3).obj里有函数,undefined,则序列化的结果会把函数或 undefined丢失
4).obj里有NaN、Infinity和-Infinity,则序列化的结果会变成null
5).JSON.stringify()只能序列化对象的可枚举的自有属性,例如 如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor
6).如果对象中存在循环引用的情况也无法正确实现深拷贝
二. 定义深拷贝方法 (判断值类型,判断是否为自身属性,递归调用)
1)//实现深拷贝函数
function deepClone(data) {
const type = this.getType(data);
let obj = null;
if (type == 'array') {
obj = [];
for (let i = 0; i < data.length; i++) {
obj.push(this.deepClone(data[i]));
}
} else if (type == 'object') {
obj = {}
for (let key in data) {
if (data.hasOwnProperty(key)) {
obj[key] = this.deepClone(data[key]);
}
}
} else {
return data;
}
return obj;
}
function getType(obj) {
// tostring会返回对应不同的标签的构造函数
const toString = Object.prototype.toString;
const map = {
'[object Boolean]': 'boolean',
'[object Number]': 'number',
'[object String]': 'string',
'[object Function]': 'function',
'[object Array]': 'array',
'[object Date]': 'date',
'[object RegExp]': 'regExp',
'[object Undefined]': 'undefined',
'[object Null]': 'null',
'[object Object]': 'object',
};
if (obj instanceof Element) {
return 'element';
}
return map[toString.call(obj)];
}
2) 方法2
function deepCopy(origin,target){
targe t= target || {};
for(let i in origin){
if( origin.hasOwnProperty(i) ){
if(typeoforigin[i]==='object'){
target[i]=Array.isArray(origin[i])?[]:{};
deepCopy(origin(i),target(i));
}else{
target(i)=origin(i);
}
}}returntarget;}
3)结构化拷贝
let origin = {
// ...
}
function structuralClone(obj) {
return new Promise(resolve => {
const {port1, port2} = new MessageChannel();
port2.onmessage = ev => resolve(ev.data);
port1.postMessage(obj);
});
}
const target = await structuralClone(origin);