浅拷贝与深拷贝

  数据类型:说到拷贝,就首先需要谈谈堆栈和数据类型了,数据类型分为基本数据类型和引用数据类型,基本数据类型包括number,string,boolean,null 和 undefined这五类,而引用数据类型是由基本数据类型组成的复杂的对象,而深拷贝本身只针对较为复杂的object类型的数据。

  堆和栈内存:接下来说一下堆栈的存储空间,基本数据类型的名和值是都存在栈内中的,即有名可以直接读出值;而对于引用数据类型,它的名也是存在栈内存中,而它的真正的值是存在堆内存中的,那么它的名和值是怎么联系起来的呢,就是通过也存在栈内存中的真正的值在堆内存中的存储路径,即引用类型的数据在栈中存储的是名和值对应的引用地址。

  深拷贝和浅拷贝:

1、使用数据类型

  深拷贝和浅拷贝只针对像 ObjectArray 这样的复杂对象的,String,Number等简单类型不存在深拷贝。

2、浅拷贝

  因为浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制。在JavaScript中,对于ObjectArray这类引用类型值,当从一个变量向另一个变量复制引用类型值时,这个值的副本其实是一个指针,两个变量指向同一个堆对象,改变其中一个变量,另一个也会受到影响。所以浅拷贝会导致 obj.arrshallowObj.arr 指向同一块内存地址,当修改obj.arr的值时,shallowObj.arr的值同样会被修改
 
3、深拷贝
  而深拷贝则不同,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深拷贝的方法递归复制到新对象上。这就不会存在上面 objshallowObjarr 属性指向同一个对象的问题。当修改obj.arr的值时,shallowObj.arr的值不会被修改,仍然为原值
 
  实现深拷贝的方法:
  1、可以递归去复制数据的所有层级的属性
function cloneDeeply(obj){
  //定义一个拷贝的对象 let objClone
= Array.isArray(obj)?[]:{};
  //传入的数据是对象类型的
if(obj && typeof obj==="object"){ for(key in obj){
        //判断是否是自身的属性方法,所有函数和原型成员会被有意忽略
if(obj.hasOwnProperty(key)){ //判断ojb子元素是否为对象,如果是,递归复制 if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //如果不是,简单复制 objClone[key] = obj[key]; } } } } return objClone; }
 
  2、JSON.parse(JSON.stringify(obj))方法实现深拷贝
  该用法简单,然而使用这种方法会有一些隐藏的坑:因为在序列化JavaScript对象时,所有函数和原型成员会被有意忽略。故只能拷贝纯json的,不能拷贝包含函数的对象)。
通俗点说,JSON.parse(JSON.stringfy(X)),其中X只能是NumberStringBooleanArray, 扁平对象,即那些能够被 JSON 直接表示的数据结构。
  
function cloneDeeply(obj){
    let _obj = JSON.stringify(obj),
        objClone = JSON.parse(_obj);
    return objClone
}    
  3、另外JQuery也提供了一个对象扩展的方法extend进行属性的深浅复制,可配置  

  jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。

  注意:1. 如果只为$.extend()指定了一个参数,则意味着参数target被省略。此时,target就是jQuery对象本身。通过这种方式,我们可以为全局对象jQuery添加新的函数。
     2. 如果多个对象具有相同的属性,则后者会覆盖前者的属性值。

  4、特殊情况
  slice的一级是深拷贝,多级则是浅拷贝(记住深拷贝是拷贝对象所以层级的属性)
  es6中的展开符号... 也是浅拷贝

参考链接:https://www.jianshu.com/p/68e563c54f63
       https://www.cnblogs.com/echolun/p/7889848.html#undefined