javascript淺拷貝深拷貝及深拷貝的幾種方法

javascript的深拷貝和淺拷貝問題幾乎是面試必問的問題。好記性不如爛筆頭,特此來記錄一下本身對深拷貝淺拷貝的理解。javascript

顧名思義,拷貝就是copy複製,在js中能夠淺而理解爲對一個對象或者數組的複製。可是複製後的對象或者數組是不是和原來的對象指向同一個地址內存仍是新開闢了一個地址內存,這就衍生出了javascript的深拷貝和淺拷貝的問題了;深複製和淺複製只針對像 Object, Array 這樣的複雜對象的。簡單來講,淺複製只複製一層對象的屬性,而深複製則遞歸複製了全部層級。java

1、javascript淺拷貝面試

淺拷貝:只複製一層對象屬性,能夠理解爲,只複製對象的基本屬性類型,而基本屬性類型是存放在棧內存中的,能夠直接修改訪問的,因此當淺拷貝時,拷貝的對象只是拷貝了原對象的屬性,而值都是指向同一個棧內存中的數據,當對象屬性值發生修改時,原對象也會被修改。以下示例:正則表達式

let arr1 = { color:'red', name:'apple', weight:'100g', detail:{ big:'true', eating:'no' } }; let arr2; arr2 = arr1; arr2.color = 'black'; console.log(arr2); console.warn(arr1);

輸出值:數組

能夠看到,當arr2的color發生變化時,被複制的對象arr1的color值也發生了變化。app

可是在實際項目應用中,咱們複製了某個對象以後絕大多數狀況下都是不但願被複制的對象的值會發生變化,這裏就涉及到javascript的深拷貝問題以及他的實現。函數

2、javascript深拷貝性能

深拷貝:它不只將原對象的各個屬性逐個複製出去,並且將原對象各個屬性所包含的對象也依次採用深複製的方法遞歸複製到新對象上。這就不會存在上面 obj 和 shallowObj 的 arr 屬性指向同一個對象的問題。這是我從某官網看來的解釋,我感受挺繞的,結合對象來看,深拷貝存在於對象這種引用類型中,而引用類型的數據是存在堆內存上的,變量保存的是一個指針,這個指針指向另外一個位置。當須要訪問引用類型(如對象,數組等)的值時,首先從棧中得到該對象的地址指針,而後再從堆內存中取得所需的數據。深拷貝能夠看作是在堆內存中新開闢了一個內存空間,複製後的對象的屬性所指的指針會指向新開闢的內存空間的地址。因此複製後的對象對屬性值進行修改不會影響原對象的屬性值。spa

那如何實現深拷貝呢?3d

一、經過JSON.parse(JSON.stringify(arr))接上面的例子:

let arr3 = JSON.parse(JSON.stringify(arr1)); arr3.color="balck"; console.log(arr3); console.warn(arr1);

輸出結果:

這個方法我以爲是最簡潔的,可是它有一些弊端:

a、對於正則表達式類型、函數類型等沒法進行深拷貝(並且會直接丟失相應的值)

b、深拷貝以後,無論這個對象原來的構造函數是什麼,在深拷貝以後都會變成Object

c、若是對象中存在循環引用的狀況也沒法正確處理。

二、經過for循環遞歸調用

function deepClone(obj){ //判斷obj是不是數組
        let objClone = Array.isArray(obj)?[]:{}; if(obj && typeof obj==="object"){ for(key in obj){ if(obj.hasOwnProperty(key)){ //判斷ojb子元素是否爲對象,若是是,遞歸複製
                    if(obj[key]&&typeof obj[key] ==="object"){ objClone[key] = deepClone(obj[key]); }else{ //若是不是,簡單複製
                        objClone[key] = obj[key]; } } } } return objClone; } var arr4 = deepClone(arr1); arr4.name='bananer'; console.log(arr4); console.warn(arr1);

輸出結果:

可是,這樣的深拷貝進行的循環遞歸調用,若是對象數據量龐大顯然會影響性能,因此通常在項目中不多使用,循環進行深拷貝,能夠考慮其餘方式來實現對象值的複製引用。

三、數組concat方法

let arr4 = [1,2,3] let arr5 = [].concat(arr4) arr5.push(4) console.log(arr4, arr5, 'deep copy') // [1,2,3] [1,2,3,4]

四、js擴展運算符(...)

let arr8 = [1,2,3] let arr9 = [...arr8] arr9.push(4) console.log(arr8, arr9, 'deep copy 2') // [1,2,3] [1,2,3,4]
相關文章
相關標籤/搜索