一、变量值分为两种类型:
基本类型(String、Number、Bollean、Undefined、Null、Symbol(Es6))
拷贝时,拷贝值和被拷贝值互不影响,在内存中时两块地址
引用类型(Object、Array、Function、Date、RegExp、Error等(Set、Map)=>es6)
拷贝时,拷贝值和被拷贝值是指向关系,一同指向内存中的一个对象,修改其中一个对象的值,另一个对象值也会改变
二、浅拷贝
创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象
Object.assign(target(新对象),source(被拷贝对象))
1、不会拷贝对象继承的属性
2、不会拷贝不可枚举的属性
3、不会拷贝属性的数据属性/访问器属性
4、可拷贝symbol类型
example:
var obj1 = {
a:{
b:1
},
sym:Symbol(1)
};
Object.defineProperty(obj1,'innumerable',{
value:'不可枚举属性',
enumerable:false
});
var obj2 = {};
O
Object.assign(obj2,obj1)
o
obj1.a.b = 2;
c
console.log('obj1',obj1);
obj1 = {
a:{
b:2 // 存在堆内存指向问题
},
sym:Symbol(1),
'innumerable': 不可枚举属性
};
console.log('obj2',obj2);
obj2 = {
a:{
b:2
},
sym:Symbol(1) //symbol类型被复制
//不可枚举的属性被忽略
}
可扩展运算符
可以看出,依然存在堆内存指向问题
Array.prototype.slice()
slice() 方法返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。
语法: arr.slice(begin, end);
在ES6以前,没有剩余运算符,Array.from的时候可以用 Array.prototype.slice将arguments类数组转为真正的数组,它返回一个浅拷贝后的的新数组
三、深拷贝
将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象
简单拷贝
Json.stringify()
把一个对象序列化成为一个Json字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON。parse()反序列化将JSON将字符串变为一个新的对象。
通过JSON.stringify实现深拷贝有几点要注意
拷贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
无法拷贝不可枚举的属性,无法拷贝对象的原型链
拷贝Date引用类型会变成字符串
拷贝RegExp引用类型会变成空对象
对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
无法拷贝对象的循环应用(即obj[key] = obj)