深入理解JavaScript的深拷貝和淺拷貝


為了更好的理解js的深淺拷貝,我們先來理解一些js基本的概念 —— Javascript有五種基本數據類型(也就是簡單數據類型),它們分別是:Undefined,Null,Boolean,Number和String。還含有一種復雜的數據類型(也叫引用類型),就是對象

 注意Undefined和Null的區別,Undefined類型只有一個值,就是undefined,Null類型也只有一個值,也就是null

 

Undefined 其實就是已聲明未賦值的變量輸出的結果

null 其實就是一個不存在的對象的結果

var a;
console.log(a)//undefined

console.log(document.getElementById('asdd'))//沒有id為asdd的節點,輸出null

基本數據類型與引用數據類型

1. 對於基本數據類型

他們的值在內存中占據着固定大小的空間,並被保存在棧內存中。當一個變量向另一個變量復制基本類型的值,會創建這個值的副本,並且我們不能給基本數據類型的值添加屬性

 

var x = 1;
var y = x;
x.name = 'hanna';
console.log(y); //1
console.log(x.name); //undefined

 

上面的代碼中,x是基本數據類型(Number), y是x的一個副本,它們兩者都占有不同位置但相等的內存空間,只是它們的值相等,若改變其中一方,另一方不會隨之改變。

 

2. 對於引用類型

復雜的數據類型即是引用類型,它的值是對象,保存在堆內存中,包含引用類型值的變量實際上包含的不是對象本身,而是一個指向該對象的指針。從一個變量向另一個變量復制引用類型的值,復制的其實是指針地址而已,因此兩個變量最終都指向同一個對象

 

var obj = {
   name:'Hanna Ding',
   age: 22
}
var obj2 = obj;
obj2['c'] = 5;
console.log(obj); //Object {name: "Hanna Ding", age: 22, c: 5}
console.log(obj2); //Object {name: "Hanna Ding", age: 0, c: 5}

 

我們可以看到obj賦值給obj2后,但我們改變其中一個對象的屬性值,兩個對象都發生了改變,根本原因就是obj和obj2兩個變量都指向同一個指針,賦值時只是復制了指針地址,它們指向同一個引用,所以當我們改變其中一個的值就會影響到另一個變量的值。

 

01 淺拷貝

 其實上面那段代碼就是淺拷貝,有時候我們只是想備份數組,但是只是簡單讓它賦給一個變量,改變其中一個,另外一個就緊跟着改變,但很多時候這不是我們想要的

var arr = [1, 2, 3, '4'];

var arr2 = arr;
arr2[1] = "test"; 
console.log(arr); // [1, "test", 3, "4"]
console.log(arr2); // [1, "test", 3, "4"]

02 深拷貝

(1)數組

對於數組我們可以使用slice() 和 concat() 方法來解決上面的問題

slice 

 

var arr = ['a', 'b', 'c'];
var arrCopy = arr.slice(0);
arrCopy[0] = 'test'
console.log(arr); // ["a", "b", "c"]
console.log(arrCopy); // ["test", "b", "c"]

 

concat

var arr = ['a', 'b', 'c'];
var arrCopy = arr.concat();
arrCopy[0] = 'test'
console.log(arr); // ["a", "b", "c"]
console.log(arrCopy); // ["test", "b", "c"]

知識點補充:

  • arrayObj.slice(start, [end]) 該方法返回一個 Array 對象,其中包含了 arrayObj 的指定部分。不會改變原數組
  • arrayObj.concat() 方法用於連接兩個或多個數組。該方法不會改變現有的數組,而僅僅會返回被連接數組的一個副本。

其實也就是下面這么個意思。。。但還是用上面的方法來實現比較簡單高效些

function deepCopy(arr1, arr2) {
   for (var i = 0; i < arr1.length; ++i) {
       arr2[i] = arr1[i];
   }
}

 

(2)對象

對象的深拷貝實現原理: 定義一個新的對象,遍歷源對象的屬性 並 賦給新對象的屬性

var obj = {
   name:'Hanna Ding',
   age: 22
}

var obj2 = new Object();
obj2.name = obj.name;
obj2.age = obj.age

obj.name = 'xiaoDing';
console.log(obj); //Object {name: "xiaoDing", age: 22}
console.log(obj2); //Object {name: "Hanna Ding", age: 22}

理解了以上的基本思想,我們就可以封裝一個方法 deepCopy來實現對象的深拷貝,代碼如下

var obj = {
    name: 'Hanna',
    age: 22
}
var deepCopy = function (source) {
    var result = {};            
    for(var key in source) {                
        if(typeof source[key] === 'object') {
            result[key] = deepCopy(source[key])
        } else {
            result[key] = source[key]
        }
    }            
    return result;
}

var objCopy = deepCopy(obj)
obj.name = 'ding';
console.log(obj);//Object {name: "ding", age: 22}
console.log(objCopy);//Object {name: "Hanna", age: 22}

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM