JS中的深拷貝與淺拷貝

JS中的深拷貝與淺拷貝

說到深淺拷貝的時候就不得不說一下JS中的變量類型了:javascript

  • 基本類型: undefinednullbooleannumberstring, 按值存放在棧內存中的簡單數據段, 能夠直接訪問.
  • 引用類型: 存放在堆內存中的對象, 變量保存的是一個指向存放數據位置的指針. 訪問引用類型(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;
}
相關文章
相關標籤/搜索