# js 数组对象深拷贝

结论:对象的拷贝不能采用直接赋值的方式。


# 背景


踩过的坑如下:



formData本来是父组件传过来的,但是我不想直接用,于是我直接赋值给一个formDataCopy的对象。


但是诡异的事情发生了,就是在我填写自己的表单组件的时候,一旦表单的数据发生的变化时,本来是formDataCopy的值发生变化,但是‘formDataDefault值’ 这个字符串却被打印出来,也就是说formData改变了。


奇怪,formData是父组件传过来的值怎么会改变呢?


经过一番挣扎,才发现formDataCopy使用的是简单的赋值,导致formDataCopy和formData指向相同的对象。


formDataCopy一改变,formData就会跟着变。


以上是背景,所以我就对浅拷贝和深拷贝进行了总结:


# 浅拷贝


什么是浅拷贝:两者是指向一个对象。


# 对象的浅拷贝


1、对象的直接遍历赋值。


2、ES6中的 var copyObj = Object.assign({}, obj);


3、ES7扩展运算符 var copyObj = { ...obj }


4、Jquery浅拷贝 var copiedObject = jQuery.extend({}, originalObject)   如果改变了originalObject,copiedObject 也会变。


# 数组的浅拷贝


(两者指向不同的对象,但是只能拷贝一层)


  • array.concat();
  • array.slice(0);


如果该元素是个对象引用 (不是实际的对象),slice 会拷贝这个对象引用到新的数组里。两个对象引用都引用了同一个对象。如果被引用的对象发生改变,则新的和原来的数组中的这个元素也会发生改变,所以是浅拷贝。


对于字符串、数字及布尔值来说(不是 String、Number 或者 Boolean 对象),slice 会拷贝这些值到新的数组里。在别的数组里修改这些字符串或数字或是布尔值,将不会影响另一个数组。


也就是说,如果原数组改变的是基本数据类型,比如String,Boolean,Number的数据,不会影响到新数组;
但是如果改变的是对象或者数组中的数据,是会影响到新数组的,也也就是对于对象或者数组,新旧数组指向的是一个对象。


# 深拷贝


(下面说的深拷贝是基本对象的深拷贝,不考虑对象的复杂属性,比如set,get,Function等)


1、最简单的方式 JSON.parse(JSON.stringify(Obj)) 这种方法使用较为简单,可以满足基本的深拷贝需求,而且能够处理JSON格式能表示的所有数据类型,但是对于正则表达式类型、函数类型等无法进行深拷贝(而且会直接丢失相应的值)。


2、jQuery深拷贝 var copiedObject = $.extend(true, {}, originalObject)


3、手动写递归方式


var array = [
  { number: 1 },
  { number: 2 },
  { number: 3 }
];
function copy (obj) {
       var newobj = obj.constructor === Array ? [] : {};
       if(typeof obj !== 'object'){
           return;
       }
       for(var i in obj){
          newobj[i] = typeof obj[i] === 'object' ? copy(obj[i]) : obj[i];
       }
       return newobj
}
var copyArray = copy(array)
copyArray[0].number = 100;
console.log(array); //  [{number: 1}, { number: 2 }, { number: 3 }]
console.log(copyArray); // [{number: 100}, { number: 2 }, { number: 3 }] 


# 参考文档


https://www.cnblogs.com/penghuwan/p/7359026.html


https://github.com/wengjq/Blog/issues/3