一、变量值分为两种类型:
    基本类型(String、Number、Bollean、Undefined、Null、Symbol(Es6))
    拷贝时,拷贝值和被拷贝值互不影响,在内存中时两块地址
    引用类型(Object、Array、Function、Date、RegExp、Error等(Set、Map)=>es6)
    拷贝时,拷贝值和被拷贝值是指向关系,一同指向内存中的一个对象,修改其中一个对象的值,另一个对象值也会改变
    image.png
    二、浅拷贝
    创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象
    Object.assign(target(新对象),source(被拷贝对象))
    1、不会拷贝对象继承的属性
    2、不会拷贝不可枚举的属性
    3、不会拷贝属性的数据属性/访问器属性
    4、可拷贝symbol类型
    example:

    1. var obj1 = {
    2. a:{
    3. b:1
    4. },
    5. sym:Symbol(1)
    6. };
    7. Object.defineProperty(obj1,'innumerable',{
    8. value:'不可枚举属性',
    9. enumerable:false
    10. });
    11. var obj2 = {};
    12. O
    13. Object.assign(obj2,obj1)
    14. o
    15. obj1.a.b = 2;
    16. c
    17. console.log('obj1',obj1);
    18. obj1 = {
    19. a:{
    20. b:2 // 存在堆内存指向问题
    21. },
    22. sym:Symbol(1),
    23. 'innumerable': 不可枚举属性
    24. };
    25. console.log('obj2',obj2);
    26. obj2 = {
    27. a:{
    28. b:2
    29. },
    30. sym:Symbol(1) //symbol类型被复制
    31. //不可枚举的属性被忽略
    32. }

    可扩展运算符
    image.png
    可以看出,依然存在堆内存指向问题

    Array.prototype.slice()

    slice() 方法返回一个新的数组对象,这一对象是一个由 begin和 end(不包括end)决定的原数组的浅拷贝。原始数组不会被改变。

    语法: arr.slice(begin, end);
    在ES6以前,没有剩余运算符,Array.from的时候可以用 Array.prototype.slice将arguments类数组转为真正的数组,它返回一个浅拷贝后的的新数组
    image.png
    三、深拷贝
    将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象
    简单拷贝
    image.png
    Json.stringify()
    把一个对象序列化成为一个Json字符串,将对象的内容转换成字符串的形式再保存在磁盘上,再用JSON。parse()反序列化将JSON将字符串变为一个新的对象。
    image.png
    通过JSON.stringify实现深拷贝有几点要注意
    拷贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
    无法拷贝不可枚举的属性,无法拷贝对象的原型链
    拷贝Date引用类型会变成字符串
    拷贝RegExp引用类型会变成空对象
    对象中含有NaN、Infinity和-Infinity,则序列化的结果会变成null
    无法拷贝对象的循环应用(即obj[key] = obj)