結論:對象的拷貝不能采用直接賦值的方式。
背景
踩過的坑如下:
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 }]