js中如何復制一個數組(淺復制、深復制)

在js中,我們經常會用到數組復制,Array是引用類型,如果用arrA=arrB簡單的把一個數組賦值,並沒有創造出一個新數組,arrA和arrB其實指向的還是同一個地址,改變一個另一個也會隨之改變,很明顯這並不是我們想要的

  var arr = [1, 2, 3];
  var newArr = arr;
  arr.push(4);
  console.log(newArr1);  // [1, 2, 3, 4]

下面介紹數組的淺復制

(適用於數組並不復雜,即數組中沒有嵌套對象或者嵌套數組)

方法一:concat()

  • concat()方法用於連接兩個或多個數組;
  • concat() 方法不會更改現有數組,而是返回一個新數組,其中包含已連接數組的值。
  var arr = [1, 2, 3];
  var newArr = arr.concat();
  arr.push(4);
  console.log(newArr); // [1, 2, 3]

方法二:slice()

  • slice() 方法以新的數組對象,返回數組中被選中的元素;
  • slice() 方法選擇從給定的 start 參數開始的元素,並在給定的 end 參數處結束,但不包括;
  • slice() 方法不會改變原始數組;
  var arr = [1, 2, 3];
  var newArr = arr.slice();
  arr[0] = 10;
  console.log(arr);// [10, 2, 3]
  console.log(newArr);// [1, 2, 3]

方法三:擴展運算符

  var arr = [1, 2, 3];
  var [ ...newArr ] = arr;
  arr[0] = 10;
  console.log(arr); // [10, 2, 3]
  console.log(newArr);// [1, 2, 3]

方法四: Object.assign()

 var arr = [1, 2, 3];
 var newArr = Object.assign([], arr);
 arr[0] = 10;
 console.log(arr);// [10, 2, 3]
 console.log(newArr);// [1, 2, 3]

如果數組元素是對象或者數組,上面四種方法就會隻拷貝數組或者對象的引用,如果我們對其中一個數組進行修改,另一個數組也會發生變化

比如:

  var arr = [ { a: 1 }, [ 1, 2 ], 3 ];
  let newArr = arr.concat();
  arr[0].a = 2;
  console.log(arr); // [ { a: 2 }, [ 1, 2 ], 3 ]
  console.log(newArr);// [ { a: 2 }, [ 1, 2 ], 3 ] 值被影響

下面是深復制

(可以完全拷貝一個數組,即使嵌套瞭對象或者數組,兩者也不會互相影響)

方法一:JSON.parse(JSON.stringify(arr))

  var arr = [ { a: 1 }, [ 1, 2 ], 3 ];
  // let newArr = JSON.parse(JSON.stringify(arr));
  let newArr = arr.concat();
  arr[0].a = 2;
  console.log(arr); // [ { a: 2 }, [ 1, 2 ], 3 ]
  console.log(newArr);// [ { a: 1 }, [ 1, 2 ], 3 ]

但是該方法是有局限性的

  • 會忽略 undefined
  • 會忽略 symbol
  • 不能序列化函數
  • 不能解決循環引用的對象

比如下面這個例子:

let a = {
  age: undefined,
  sex: Symbol('male'),
  jobs: function() {},
  name: 'sun'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "sun"}

方法二:通用方法(數組或對象)

拷貝的時候判斷屬性值的類型,如果是對象,繼續遞歸調用深拷貝函數(簡易版)

  var deepCopy = function(obj) {
    // 判斷是否是對象
    if (typeof obj !== 'object') return;
    // 判斷obj類型,根據類型新建一個對象或者數組
    var newObj = obj instanceof Array ? [] : {}
    // 遍歷對象,進行賦值
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        let val = obj[key];
        // 判斷屬性值的類型,如果是對象,遞歸調用deepCopy
        newObj[key] = typeof val === 'object' ? deepCopy(val) : val
      }
    }
    return newObj
  }

方法三:利用lodash的深拷貝函數

_.cloneDeep(value)

其中value就是要深拷貝的值

簡單例子

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

在Vue中使用

安裝

npm i --save lodash

在main.js中引入

import _ from 'lodash';
Vue.prototype._ = _;

使用

let newObj = this._.cloneDeep(oldObj)

總結

以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。

推薦閱讀: