js 對象拷貝的三種方法,深拷貝函數。


js 對象拷貝的三種方法

以下面數據格式obj 為主:

  const obj = {
    data: 1,
    un: undefined,
    info: {
      d: 2
    },
    fn: function() {
      console.log('Function')
    },
    get c() {
      return info.d
    }
  }

Object.assign

const ObjA = Object.assign({}, obj)
ObjA.data = 'a'
ObjA.info.d = 'b'

const ObjB = Object.assign({}, obj)
ObjB.data = 'c'
ObjB.info.d = 'd'

console.log(ObjA)
console.log(ObjB)
/* 
==========輸出==========
{ data: 'a', info: { d: 'd' }, un: undefined, fn: [Function: fn] }
{ data: 'c', info: { d: 'd' }, un: undefined, fn: [Function: fn] }
*/

我們會發現info.d 內容相等,說明Object.assign無法拷貝深層次內容,適用於淺層拷貝。

JSON.stringify & JSON.parse

const ObjA = JSON.parse(JSON.stringify(obj))
ObjA.data = 'a'
ObjA.info.d = 'b'

const ObjB = JSON.parse(JSON.stringify(obj))
ObjB.data = 'c'
ObjB.info.d = 'd'
console.log(ObjA)
console.log(ObjB)

/* 
==========輸出==========
{ data: 'a', info: { d: 'b' }, c: 2 }
{ data: 'c', info: { d: 'd' }, c: 2 }
*/

我們將源對象轉換為字符串,再轉換為新對象雖然解決了深層次拷貝的問題,但我們會發現對象中的Functionundefined 無法拷貝,並且將c: [Getter] 直接轉換成了鍵值對 c:2。

Object.create

const ObjA = Object.create(obj)
ObjA.data = 'a'
ObjA.info.d = 'b'

const ObjB = Object.create(obj)
ObjB.data = 'c'
ObjB.info.d = 'd'

console.log(ObjA)
console.log(ObjB)
console.log(ObjA.__proto__)
console.log(ObjB.__proto__)
/* 
==========輸出==========
{ data: 'a' }
{ data: 'c' }
{ data: 1, info: { d: 'd' }, fn: [Function: fn], c: [Getter] }
{ data: 1, info: { d: 'd' }, fn: [Function: fn], c: [Getter] }
*/

Object.create 原型鏈繼承,也可以達到內容淺層拷貝。

總結:

賦值 淺層拷貝 深層拷貝 getter/setter
Object.assign ok no no
JSON.stringify ok ok no
Object.create ok no ok

深拷貝函數


function checkType(any) {
  return Object.prototype.toString.call(any).slice(8, -1)
}
function clone(any){
  if(checkType(any) === 'Object') { // 拷貝對象
    let o = {};
    for(let key in any) {
      o[key] = clone(any[key])
    }
    return o;
  } else if(checkType(any) === 'Array') { // 拷貝數組
    var arr = []
    for(let i = 0,leng = any.length;i<leng;i++) {
      arr[i] = clone(any[i])
    }
    return arr;
  } else if(checkType(any) === 'Function') { // 拷貝函數
    return new Function('return '+any.toString()).call(this)
  } else if(checkType(any) === 'Date') { // 拷貝日期
    return new Date(any.valueOf())
  } else if(checkType(any) === 'RegExp') { // 拷貝正則
    return new RegExp(any)
  } else if(checkType(any) === 'Map') { // 拷貝Map 集合
    let m = new Map()
    any.forEach((v,k)=>{
      m.set(k, clone(v))
    })
    return m
  } else if(checkType(any) === 'Set') { // 拷貝Set 集合
    let s = new Set()
    for(let val of any.values()) {
      s.add(clone(val))
    }
    return s
  }
  return any;
}
// 測試

var a = {
  name: '張三',
  skills: ['踢球', '跑步', '打羽毛球'],
  age: 18,
  love: {
    name: '小紅',
    age: 16
  },
  map: new Map([['aaa', '123']]),
  fn:function(a){
    console.log(`我的名字叫${this.name}` + a)
  },
  set: new Set([1,2,3,4,5])
}
var newA = clone(a)
a.age = 100
a.love.age = 100
a.set.add('1123')
a.skills.push('計算機')
a.name = '小梅'
a.map.set('name', '小明')

console.log(a)
console.log(newA)

a.fn('a')
newA.fn('newA')


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM