ES6中數組和對象的擴展運算符拷貝問題以及經常使用的深淺拷貝方法

  在ES6中新增了擴展運算符能夠對數組和對象進行操做。有時候會遇到數組和對象的拷貝,可能會用到擴展運算符。那麼這個擴展運算符究竟是深拷貝仍是淺拷貝呢?es6

一.、使用擴展運算符拷貝數組

  首先是下面的代碼。ui

let a = [1,2,3];
let b = [...a];
a == b // false

  結果是false,這是很容易知道的,畢竟這個賦值操做符是由區別的。接下來將數組的只進行改變,又會怎樣呢;this

let a = [1,2,3];
let b = [...a];
a[0] = 11;
console.log(a); // [ 11, 2, 3 ]
console.log(b); // [ 1, 2, 3 ]

  發現a的值發生改變以後b的值並無發生改變。因此就是深拷貝了嗎?別急,接下來將數組中的元素設爲引用類型。spa

let a = [1,2,[1,2,3]];
let b = [...a];
a[2][1] = 11;
console.log(a); // [ 1, 2, [ 1, 11, 3 ] ]
console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
console.log(a[2] === b[2]); // true
 

  此次的結果就有意思了,若是改變數組中的引用類型的元素中的值,此時a和b的值都會改變,而且a和b中的引用類型全等,也就是說地址是相同的。那麼爲何是這樣的呢?插件

二.、緣由code

  首先此分析僅爲本人目前的認知。對象

  對於數組中的擴展運算符只是一個淺拷貝,僅對引用類型數據的第一層進行了拷貝,而假若再深的層次就不會進行拷貝。blog

  另外對象的擴展運算符和數組是同樣的。遞歸

let a = {
    name : "Jyy",
    msg : {
        age : 29
    }
}
let b = {...a};
console.log(a == b);    // false
console.log(a.msg == b.msg);    // true;
a.msg = {
    age : "28"
}
console.log(a); // { name: 'Jyy', msg: { age: '28' } }
console.log(b); // { name: 'Jyy', msg: { age: 29 } }

3、深拷貝和淺拷貝的方法

  1.淺拷貝方法

    上面的例子已經看出來es6中的擴展運算符僅僅對引用類型進行了第一層的拷貝。除了es6的擴展運算符還有其餘方法

    對象:

      使用Object.assign()

        Object.assign()用於對象的合併,若是第一個參數爲{},則可對後面的對象參數進行拷貝

let a = {
    name : "Jyy",
    msg : {
        age : 29
    }
}
let b = Object.assign({},a);
console.log(a == b);    // false
console.log(a.msg == b.msg);    // true;
a.msg = {
    age : "28"
}
console.log(a); // { name: 'Jyy', msg: { age: '28' } }
console.log(b); // { name: 'Jyy', msg: { age: 29 } }

    數組: 

      數組的淺拷貝的方法不少

      a.使用slice()

        slice能夠截取數組中部分的元素,若參數爲空,則可對數組進行淺拷貝

let a = [1,2,[1,2,3]];
let b = a.slice();
console.log(a == b);    // false
a[2][1] = 11;
a[0] = 11;
console.log(a); // [ 11, 2, [ 1, 11, 3 ] ]
console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
console.log(a[2] == b[2]);  // true

      b.使用concat()

        concat能夠對數組進行合併,若參數爲空,亦可對數組進行淺拷貝

let a = [1,2,[1,2,3]];
let b = a.concat();
console.log(a == b);    // false
a[2][1] = 11;
a[0] = 11;
console.log(a); // [ 11, 2, [ 1, 11, 3 ] ]
console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
console.log(a[2] == b[2]);  // true

      c.使用Array.from()

let a = [1,2,[1,2,3]];
let b = Array.from(a);
console.log(a == b);    // false
a[2][1] = 11;
a[0] = 11;
console.log(a); // [ 11, 2, [ 1, 11, 3 ] ]
console.log(b); // [ 1, 2, [ 1, 11, 3 ] ]
console.log(a[2] == b[2]);  // true

  2.深拷貝

    對於深拷貝,數組和對象的方法是一致的

    a.遞歸方法,就是用for循環一層一層的進行拷貝,具體代碼就不寫了

    b.JSON.parse()

      這個方法一般用於調用接口傳參或者是返回的字符串數據轉成對象。

let a = {
    name : "JYY",
    age : "25",
    msg : {
        addr : "hebei"
    }
}
b = JSON.parse(JSON.stringify(a));
console.log(a == b);    // false
console.log(a.msg == b.msg);    // false
a.msg.addr = "chengde";
console.log(a); // { name: 'JYY', age: '25', msg: { addr: 'chengde' } }
console.log(b); // { name: 'JYY', age: '25', msg: { addr: 'hebei' } }

      這個方法的弊端就是undefinedfunctionsymbol 會在轉換過程當中被忽略

let a = {
    name : "JYY",
    age : "25",
    msg : {
        addr : "hebei"
    },
    speek : function(){
        console.log(this.name);
    }
}
b = JSON.parse(JSON.stringify(a));
console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }
console.log(b); // { name: 'JYY', msg: { addr: 'hebei' } }

    c.使用第三方插件

      好比lodash的深拷貝

const _ = require("lodash");
let syb = Symbol('jyy');
let a = {
    name : "JYY",
    height: syb,
    age : undefined,
    msg : {
        addr : "hebei"
    },
    speek : function(){
        console.log(this.name);
    }
}
let b = _.cloneDeep(a);
console.log(a == b);    // false
console.log(a.msg == b.msg);    // false
console.log(a); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }
console.log(b); // { name: 'JYY', height: Symbol(jyy), age: undefined, msg: { addr: 'chengde' },speek: [Function: speek] }
相關文章
相關標籤/搜索