不会还有人不懂浅拷贝与深拷贝吧不会吧不会吧

331 阅读3分钟

引言

深拷贝浅拷贝是一道经典的面试题,在实际编程中也有着不可忽视的作用,本文将帮助你从0理解浅拷贝深拷贝的本质以及实现

废话不多说,先上代码

function clone(data){
if(typeof data === 'symbol'){//Symbol
    return Symbol.for(data.description);
}
else if(typeof data!= 'object'){//基本数据类型
    return data;
}
else if (data instanceof  Array){//array
     return data.map(item=>clone(item))
    //return [...data]
    }           
else if (data.constructor=== Object){//json
    let res={}
    for (let key in data){
        res[key]=clone(data[key]) ;
    }
    return res;
    // return {...data}
}
else{//系统与自定义对象
    return data.constructor(data);
}
}

五种数据类型

1.基本数据类型:数字,字符串

2.数组 与json

复制引用
    let a=[2,4,6]
    let b=a
    console.log(b) //b数组为a数组的引用对象,每当a改变数值,b将随之改变
    思考:复制引用真的一无是处吗:不是,有性能优化的考虑
浅拷贝
    const a=[2,4,6]
    const b=[...a]
    这里用了ES6的语法糖...拓展运算符把a数组复制了一边,此时b数组是全新复制一个数组对象,当改变a数组d的值时,b数组不会随之改变。到这里有同学问,深拷贝就这?当然不是了,现在目标数组只有一层,如果遇到嵌套数组呢?
    const a=[2,[8,9],4,6]
    const b=[...a]
    a[1].push(5)
    console.log(a[1])//[8,9,5]
    console.log(b[1])//[8,9,5]
    看到了吧第二层数组里面还是指向a数组的引用,同样json里面全都是一层套一层的对象处理方法与嵌套数组一样要用到我们深拷贝的方法
深拷贝
    要实现深拷贝就要用到递归的思想了,把数组一层一层地复制下去,否则只有第一层是全新的对象,第二层就会是目标数组的对象引用,关于递归的思想我们会在后面说

3.系统变量

系统变量:
    以 Date 为例子 js中有一种封装好的方法可以复制系统对象:直接把实例丢给构造函数

    let date01=new Date(2018,10,8)
    let date02=new Date(date01)
    date01.setFullYear(2020)
    console.log(date02);//Thu Nov 08 2018 00:00:00 GMT+0800 (中国标准时间)
注意:new Array()和new Object() 不能使用该方法复制,
new Object(json) 复制的还是Object对象的引用
new Array(arr) 会嵌套进arr数组,而不是复制arr数组本身

4.自定义对象 创建时考虑到要克隆,就要手动实现通过实例复制对象

class Person{
   constructor(name,age){
       if(arguments.length=1&&arguments[0] instanceof Person){
           let p=arguments[0]
           this.name=p.name
           this.age=p.age
       }else{
           this.name=name
            this.age=age
        }
   
   }
}
    let p1 =new Person('clh',18)
    let p2  =new Person(p1)
    console.log(p2==p1);//flase

5.symbol

ES6 引入了一种新的原始数据类型 Symbol ,表示独一无二的值,最大的用法是用来定义对象的唯一属性名。

Symbol.for() :带上key值

Symbol.for() 类似单例模式,首先会在全局搜索被登记的 Symbol 中是否有该字符串参数作为名称的 Symbol 值,如果有即返回该 Symbol 值,若没有则新建并返回一个以该字符串参数为名称的 Symbol 值,并登记在全局环境中供搜索。
let s1=Symbol('a');
let s2=Symbol(s1.description)
console.log(s2);//Symbol(a)
s1===s2//false
创建的时候就需要考虑克隆
let s1=Symbol.for('a');
let s2=Symbol.for(s1.description)
console.log(s2);//Symbol(a)
s1===s2//false