在JavaScript中,數據類型分為兩大類:基本數據類型和復雜數據類型。基本數據類型包括Number、Boolean、String、Null、String),而復雜數據類型包括Object、Function、Array。
而對於基本數據類型來說,復制一個變量值,本質上就是copy了這個變量。一個變量值的修改,不會影響到另外一個變量。
let val = 123; let copy = val; console.log(copy); //123 val = 456; //修改val的值對copy的值不產生影響 console.log(copy); //123
而對於復雜數據類型來說,同基本數據類型實現的不太相同。對於復雜數據類型的復制,要注意的是,變量名只是指向這個對象的指針。當我們將保存對象的一個變量賦值給另一個變量時,實際上復制的是這個指針,而兩個變量都指向都一個對象。因此,一個對象的修改,會影響到另外一個對象。
// obj只是指向對象的指針 let obj = { character: 'peaceful' }; //copy變量復制了這個指針,指向同一個對象 let copy = obj; console.log(copy); //{character: 'peaceful'} obj.character = 'lovely'; console.log(copy); //{character: 'lovely'}
拷貝對象
在JavaScript中,拷貝對象分為兩種方式,淺拷貝和深拷貝。
淺拷貝指兩個不同的變量存的是同一個對象的地址,即兩個變量指向同一塊內存區域;深拷貝則是重新分配了一塊內存區域來存儲復制后的對象,兩個變量存的是真正的兩個互不影響的變量。
淺拷貝
let objA = { name: '對象A', content: '我是A' }; let copyA = objA; console.log(objA.name); // ==> "對象A" console.log(copyA.name); // ==> "對象A"
如此即得到了objA的一份淺拷貝copyA,由於指向的是同一個對象,因此在修改objA的同時也是修改了copyA,反之亦然。
Object.assign 的深拷貝與淺拷貝
Object.assign(target, …sources)
如果我們把它的第一個參數target設置為一個空對象 {},同時保證剩余的源對象sources中的屬性類型不包含引用類型,則該方法的返回值就是一個與源對象相同的但並不在同一塊內存空間另一個對象,即獲得了源對象的深拷貝。但是,如果源對象的屬性中包含某個對象,也就是這個屬性的值指向某個對象,就像下面這樣:
var obj = { name: 'obj name', content: { a: 1, b: 2 } };
則使用 Object.assign({}, obj) 時,返回的目標對象中的content屬性與源對象obj中的content屬性指向的同一塊內存區域,即對obj下的content屬性進行了淺拷貝。因此針對深拷貝,需要使用其他方法,比如自己實現一個深拷貝的方法,或者使用 JSON.parse(JSON.stringify(obj))
另一種淺拷貝 ...操作符:
let arr = {a:1,b:2} let arr2 = {...arr} arr2.a = 2 console.log(arr.a)//1 console.log(arr2.a)//2
深拷貝
我認為對於對象來說最簡單的深拷貝方法就是轉成字符串再解析
var obj = {a:1,b:2} var newObj = JSON.parse(JSON.stringify(obj)); newObj.a=3; console.log(obj);
另外一種深拷貝方法:遞歸遍歷
var obj = {a:{b:10}}; function deepCopy(obj){ if ( typeof obj != 'object' ){ // ( obj instanceof Object || obj instanceof Array ) return obj; } var newobj = {}; for ( var attr in obj) { newobj[attr] = deepCopy(obj[attr]); } return newobj; } var obj2 = deepCopy(obj); obj2.a.b = 20; alert(obj.a.b); //10