javascript的深拷贝和浅拷贝

如何区分深拷贝与浅拷贝,简单点来说,就是假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,拿人手短,如果B没变,那就是深拷贝,自食其力。

所谓深浅拷贝,都是进行复制,那么区别主要在于复制出来的新对象和原来的对象是否会互相影响,改一个,另一个也会变

浅拷贝(Shallow Copy) VS 深拷贝(Deep Copy)

javascript的深拷贝和浅拷贝

 

 

 

一、如何实现深拷贝

1 递归

function deepClone(source){    
    if(!source && typeof source !== 'object'){
      throw new Error('error arguments', 'shallowClone');    
    }    
    var targetObj = Array.isArray(source) ? [] : {};    
    for(var keys in source){       
      if(source.hasOwnProperty(keys)){          
        if(source[keys] && typeof source[keys] === 'object'){  
          targetObj[keys] = deepClone(source[keys]);   //递归      
        }else{            
          targetObj[keys] = source[keys];         
        }       
      }
    }    
    return targetObj; 
  }
var A = [{name:"jack",age:20},{name:"marry",age:18},{name:"smilth",age:28}];
var c = deepClone(A);
A[0].name = '李四';
console.log(c);
console.log(A);

javascript的深拷贝和浅拷贝

 

 

2 JSON.parse(JSON.stringify())

a.JSON.parse() 方法用来解析JSON字符串,构造由字符串描述的JavaScript值或对象。提供可选的 reviver 函数用以在返回之前对所得到的对象执行变换(操作)。

b.JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串,如果指定了一个 replacer 函数,则可以选择性地替换值,或者指定的 replacer 是数组,则可选择性地仅包含数组指定的属性。

const obj1 = {person: {name:'李四',age: 20}};
const obj2 = JSON.parse(JSON.stringify(obj1));
obj2.person.name = '王五'
console.log(obj1,obj2)

 

javascript的深拷贝和浅拷贝

 

 

这样做是真正的Deep Copy,这种方法简单易用。

但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object。

这种方法能正确处理的对象只有 Number, String, Boolean, Array, 扁平对象,即那些能够被 json 直接表示的数据结构。RegExp对象是无法通过这种方式深拷贝。

也就是说,只有可以转成JSON格式的对象才可以这样用,像function没办法转成JSON。

3 jQuery 的 extend()

本人不会JQuery请看听风是风的博客

二、实现浅拷贝的方法

简单地复制语句

2 Object.assign方法:Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象

需要注意的是:

Object.assign()可以处理一层的深度拷贝,如下:
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = Object.assign({}, obj1);
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 20, c: 30 } <-- 沒被改到
console.log(obj2);
// { a: 10, b: 100, c: 30 }

 

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

4 concat():concat方法不会改变this或任何作为参数提供的数组,而是返回一个浅拷贝,它包含与原始数组相结合的相同元素的副本

const array1 = ['a', 'b', ['c', 'f']];
const array2 = ['d', 'e'];
const array3 = array1.concat(array2);
array1[0] = 'A';
array1[2][0] = 'C'
console.log(array1,array2,array3)

javascript的深拷贝和浅拷贝

 

slice和concat方法一级属性不受影响,但是二级属性确没能拷贝成功。

javascript的深拷贝和浅拷贝

 

 

 

第一层的属性确实深拷贝,拥有了独立的内存,但更深的属性却仍然公用了地址,所以才会造成上面的问题。

 

三、参考和引用

【JS】深拷贝与浅拷贝的区别,实现深拷贝的几种方法

【 js 基础 】 深浅拷贝

上一篇:js深浅拷贝


下一篇:死锁的代码