js物件的複製方法

冰影浴火發表於2019-03-29

js物件複製

物件是js裡重要的基本型別,廣義上講js裡萬物皆物件。複製一個資料,是一個常用的需求,但是相對於基本資料型別如數字,字串等,物件複製起來要複雜的多。

// 數字的複製
var m = 666
var n = m
console.log(n) // 666
複製程式碼

物件的複製是無法這樣的,以為這樣的複製只是複製了物件的引用

var o1 = {
  m: 666,
  n: 'abc'
}
var o2 = o1
console.log(o2.m) // 666
console.log(o2.n) // abc
// 改變o1會導致o2也發生改變
o1.m = 999
o1.n = 'def'
console.log(o2.m) // 999
console.log(o2.n) // def
複製程式碼

可以看出,當原物件發生改變,複製的物件也會發生改變,這不符合我們的要求。

下面我將介紹3種複製物件的方法:

  1. 使用遞迴遍歷物件的所有可列舉屬性然後複製
var copy_1 = function (obj) {
  var o
  // 檢測傳入資料的屬性,根據資料的型別分別處理
  switch (typeof(obj)) {
    case 'undefined':
      break
    case 'string':
      o = obj + ''
      break
    case 'number':
      o = obj - 0
      break
    case 'boolean':
      o = !!obj
      break
    case 'object':
      if (obj === null) {
        o = null
      } else {
        if (Object.prototype.toString.call(obj).slice(8, -1) === 'Array') {
          o = []
          for (let v of obj) {
            o.push(copy_1(v))
          }
        } else {
          o = {}
          // 遍歷物件,並遞迴遍歷物件每一層,然後複製每層屬性
          for (let v in obj) {
            o[v] = copy_1(obj[v])
          }
        }
      }
      break
    default:
      o = obj
  }
  return o
}

var o1 = {
  m: 666,
  n: 'abc'
}
var o2 = copy_1(o1)
o1.m = 123
console.log(o1.m) // 123
console.log(o2.m) // 666
複製程式碼

此方法不可複製物件的getter和setter屬性,不可列舉屬性

  1. 使用es6裡的Object.assign方法
var copy_2 = function (obj) {
  var o
  if (Object.prototype.toString.call(obj).slice(8, -1) === 'Array') {
    o = []
  } else {
    o = {}
  }
  // 使用Object.assign()
  return Object.assign(o, obj)
}

var o1 = {
  m: 666,
  n: 'abc'
}
var o2 = copy_2(o1)
o1.m = 123
console.log(o1.m) // 123
console.log(o2.m) // 666
複製程式碼

此方法不可複製物件的getter和setter屬性,不可列舉屬性,物件的繼承屬性

  1. 使用getOwnPropertyDescriptors和defineProperties
var copy_3 = function (obj) {
  var o = {}
  // 獲取原物件所有屬性的描述
  var des = Object.getOwnPropertyDescriptors(obj)
  // 通過物件屬性描述建立新物件
  Object.defineProperties(o, des)
  return o
}

var o1 = {
  m: 666,
  n: 'abc'
}
var o2 = copy_3(o1)
o1.m = 123
console.log(o1.m) // 123
console.log(o2.m) // 666
複製程式碼

此方法不可複製物件的繼承屬性

以上三種方法各有各的適用範圍,為了達到各種複製需求,可以考慮綜合幾種方法來達到複製的要求。

相關文章