說到深淺拷貝的時候就不得不說一下JS中的變量類型了:javascript
undefined
、null
、boolean
、number
、string
, 按值存放在棧內存中的簡單數據段, 能夠直接訪問.object
, array
)的值時, 首先從棧中獲取到存放該數據位置的指針, 而後再從堆中取得數據.淺拷貝分兩種狀況, 拷貝源對象的引用和源對象拷貝實例, 但其屬性拷貝引用.
拷貝源的引用
eg:java
let obj1 = { a: 1 }; let obj2 = obj1; console.log(obj1 === obj2); // true obj1.a = 2; console.log(obj2.a); // 2
源對象拷貝實例, 其屬性對象拷貝引用
外層源對象是拷貝實例, 可是若是源對象的屬性元素爲複雜數據類型時, 內層元素拷貝引用. 對源對象操做時不影響拷貝對象. 但對其屬性操做時, 會改變拷貝對象屬性的值. 經常使用方法: Array.prototype.slice()
, Array.prototype.concat()
, jQuery
的$.extend({}, obj)
, Object.assign()
等. eg:prototype
let obj1 = { a: 1, b: [1, 2, 3], c: { c1: 1 } }; let obj2 = Object.assign({}, obj1); obj2.a = 2; obj2.b[0] = 2; obj2.c.c1 = 10 console.log(obj1); /** 輸出結果: { a: 1, b: [2, 2, 3], c: { c1: 10 } } **/
這上面的例子中obj1
爲源對象, obj2
爲拷貝對象. 拷貝後修改拷貝對象的屬性a
沒有影響到源對象, 修改拷貝對象的複雜數據類型屬性b
, c
後影響到源對象.指針
深拷貝事後, 源對象、拷貝對象包括其內部元素(包括複雜類型元素)都不互相干擾. 常見方法有JSON.parse(JSON.stringify(obj))
, jQuery
的$.extend(true, {}, obj)
, lodash
的_.cloneDeep
和_clone(value, true)
. eg:code
let obj1 = { a: 1, b: [1, 2, 3], c: { c1: 1 } }; let obj2 = JSON.parse(JSON.stringify(obj1)); obj2.a = 2; obj2.b[0] = 2; obj2.c.c1 = 10 console.log(obj1); /** 輸出結果: { a: 1, b: [1, 2, 3], c: { c1: 1 } } **/
最後輸出源對象(obj1
) 獲得結果是源對象未變化.
深拷貝就是增長一個指針(棧內存)申請一個新的堆內存, 並讓這個指針指向這個堆內存. 當咱們須要複製源對象而又不能修改源對象的時候, 深拷貝就是你想要的.對象
那麼是時候本身實現一個深拷貝方法了:ip
function deepclone(sObj, cObj) { cObj = cObj || (Array.isArray(sObj) ? [] : {}); for(let i in sObj) { if(typeof sObj[i] === 'object') { cObj[i] = Array.isArray(sObj[i]) ? [] : {}; deepclone(sObj[i], cObj[i]) } else { cObj[i] = sObj[i] } }; return cObj; }