手写浅拷贝与深拷贝

1,104 阅读2分钟

一.浅拷贝和深拷贝是什么? 

拷贝即为复制,我们一般通过赋值的方式可以进行拷贝一个变量的值。

例如:

当复制基本数据类型

let a = 23;
let b = a;
b = 24;
console.log(a);
console.log(b);

控制台将会输出如下:


但是当我们复制引用数据类型

let a = {name:"zhangjie"}
let b = a;
b.name = "zhangsan";
console.log(a);
console.log(b);


你会发现两者有点不同,在进行引用数据类型赋值时,当修改一个变量的值,另外一个变量的值也改变了。因为在赋值时引用数据类型复制的是地址值,假设这里的变量a的地址值为ox123,那么b复制到的只是a的地址值ox123。此时a、b指向同一块内存地址。当b的name属性值变化时,a也会一起变化。在开发中我们是不希望遇到的。存在数据的安全问题。

浅拷贝和深拷贝正是为了解决这样的问题。

浅拷贝笔者认为它只是解决了第一层拷贝问题

例如:

let a = {name:"zhangjie"}
let b = Clone.Sclone(a);
b.name = "zhangsan";
console.log(a);
console.log(b);

当进行进行浅拷贝后


此时b的改变并没有影响到a的改变。其中Clone.Sclone()为手写的浅拷贝函数。

但是如果拷贝的是这样的

let a = {name:"zhangjie",like:{    game:"wangzhe",}}
let b = Clone.Sclone(a);
b.like.game = "chiji";
console.log(a);console.log(b);


此时你发现浅拷贝就不起作用了。这个时候就应该用深拷贝了。

二.手写代码

1.浅拷贝

let Sclone =(obj)=>{        
    // 方法一        
    // let obj1 = {}        
    // obj1 = Object.assign({},obj)        
    // 方法二 
    let obj1 ={...obj}       
    return obj1    
}

正如代码中浅拷贝的自定义函数有两种,一种是用Object.assign解决,一种是采用...运算符。

如果拷贝的是数组的话

    let Sclone =(obj)=>{   
   // 方法一  let obj1 = [];      
             obj1 = Object.assign([],obj)      
   // 方法二      
   // let obj1 =[...obj]      
     return obj1  
  }

写通用的方法的话,自己可以下来写,笔者就不给出了。

2.深拷贝(重点)

let Dclone = (obj)=>{     
   function getObjclass(obj){           
 // 判断数据类型 
      let result = Object.prototype.toString.call(obj).slice(8,-1); 
      return result;       
 }        
let result;        
let  objclass = getObjclass(obj);        
console.log(objclass);        
if(objclass === "Object")        
{ 
   result = {};       
 }        
else if(objclass === "Array"){ 
   result = [];       
 }else{  
   return obj;       
 }       
 for(let key in obj)       
 {            
    let value = obj[key]; 
   // 递归取数据           
 if(getObjclass(value) === "Object"||"Array")   
 {        
    result[key] = Dclone(value);   
 }else{      
    result[key] = value;;    
 }      
 }       
   return result;  
 }

解决问题类型

let a = [1,{name:"zhangjie"}]
let b = Clone.Dclone(a);
b[1].name = "zhangsan";
console.log(a);console.log(b);



此时发现第二层的b拷贝也不会影响到a了,当然深拷贝是针对多层的。读者下来可以试一试。

欢迎大家留言,给出自己的看法,或者指出我的错误。