JS深浅拷贝

一、Object.assign(target, source)

基本数据类型的拷贝,是深拷贝;引用数据类型的拷贝,是浅拷贝

①对象复制

var source = {
      name: '库里',
      player: {
        num: 30,
        age: 34
      }
    }
var target = {}
target = Object.assign(target, source)
target.name = 'curry' // 基本类型
target.player.num = 3 // 引用类型
console.log('source:', source) // { name: '库里', player: { num: 3, age: 34 } }
console.log('target:', target) // { name: 'curry', player: { num: 3, age: 34 } }

②数组复制

var source = [
      '库里',
      {
        num: 30,
        age: 34
      }
    ]
var target = []
target = Object.assign(target, source)
target[0] = 'curry' // 基本类型
target[1].num = 3 // 引用类型
console.log('source:', source) // [ '库里', { num: 3, age: 34 } ]
console.log('target:', target) // [ 'curry', { num: 3, age: 34 } ]

二、扩展运算符(…)

基本数据类型的拷贝,是深拷贝;引用数据类型的拷贝,是浅拷贝

①对象复制

var source = {
      name: '库里',
      player: {
        num: 30,
        age: 34
      }
    }
var target = { ...source }
target.name = 'curry' // 基本类型
target.player.num = 3 // 引用类型
console.log('source:', source) // { name: '库里', player: { num: 3, age: 34 } }
console.log('target:', target) // { name: 'curry', player: { num: 3, age: 34 } }

②数组复制

var source = [
      '库里',
      {
        num: 30,
        age: 34
      }
    ]
var target = [ ...source ]
target[0] = 'curry' // 基本类型
target[1].num = 3 // 引用类型
console.log('source:', source) // [ '库里', { num: 3, age: 34 } ]
console.log('target:', target) // [ 'curry', { num: 3, age: 34 } ]

三、var target = JSON.parse(JSON.stringify(source))

无论是基本数据类型还是引用数据类型,都是深拷贝,但有些问题存在!

JSON.stringify()将 JavaScript值(通常为对象或数组)转换为 JSON 字符串

JSON.parse():将一个 JSON 字符串转换为对象或数组

①对象深复制

var source = {
      name: '库里',
      player: {
        num: 30,
        age: 34
      }
    }
var target = JSON.parse(JSON.stringify(source))
target.name = 'curry' // 基本类型
target.player.num = 3 // 引用类型
console.log('source:', source) // { name: '库里', player: { num: 30, age: 34 } }
console.log('target:', target) // { name: 'curry', player: { num: 3, age: 34 } }

②数组深复制

var source = [
      '库里',
      {
        num: 30,
        age: 34
      }
    ]
var target = JSON.parse(JSON.stringify(source))
target[0] = 'curry' // 基本类型
target[1].num = 3 // 引用类型
console.log('source:', source) // [ '库里', { num: 30, age: 34 } ]
console.log('target:', target) // [ 'curry', { num: 3, age: 34 } ]

四、var target = JSON.parse(JSON.stringify(source))深拷贝存在的问题:

  • 对象中Date类型时,序列化之后会变成字符串类型
  • 对象中有Error或RegExp类型时,序列化之后会变成空对象{}
  • 对象中有undefinedFunction类型数据的时候,序列化之后会直接丢失
  • 对象中有NaNInfinity-Infinity的时候,序列化之后value会变成null
  • 对象循环引用后,执行序列化会报错
  • 最后,深拷贝建议使用递归,安全方便
// JSON.parse(JSON.stringify())深拷贝存在的问题
let source = {
  name: '库里',
  player: {
    num: 30,
    age: 34
  },
  date: new Date(), // 深拷贝后类型会变为string
  reg: /^[1-9]$/, // 或new RegExp('[1-9]'),深拷贝后会变为空对象{}
  err: new Error('err'), // 深拷贝后会变为空对象{}
  undef: undefined, // 深拷贝后会丢失
  func: () => { console.log('func') }, // 深拷贝后会丢失
  nan: NaN, // 深拷贝后会变成null
  infinityMax: Infinity, // 深拷贝后会变成null
  infinityMin: -Infinity // 深拷贝后会变成null
}
// source.child = source // 循环引用后,深拷贝报错:TypeError: Converting circular structure to JSON
const target = JSON.parse(JSON.stringify(source))
console.log('type:', typeof source.date) // object
console.log('type:', typeof target.date) // string
console.log('source:', source)
console.log('target:', target)

五、 递归深拷贝(推荐

function deepClone (target, wm = new WeakMap()) {
  if (target === null) return target // null 直接返回
  if (target instanceof Date) return new Date(target)
  if (target instanceof RegExp) return new RegExp(target)
  // 可能是对象或者普通的值,如果是函数的不需要深拷贝
  if (typeof target !== 'object') { // 包括: boolean | number | string | undefined | function
    return target
  }
  // 防止循环引用
  if (wm.get(target)) {
    return wm.get(target)
  }
  // 实例的构造函数,就是其类原型的构造函数constructor()方法,类原型的构造函数constructor,直接指向类本身
  // obj.constructor === Object.prototype.constructor === Object
  let cloneTarget = new target.constructor()
  wm.set(target, cloneTarget)
  for (let key in target) {
    cloneTarget[key] = deepClone(target[key], wm)
  }
  return cloneTarget
}
let source = {
  name: '库里',
  player: {
    num: 30,
    age: 34
  },
  date: new Date(),
  reg: /^[1-9]$/,
  err: new Error('err'),
  undef: undefined,
  func: () => { console.log('func') },
  nan: NaN,
  infinityMax: Infinity,
  infinityMin: -Infinity
}
source.self = source // 循环引用,即对象的属性间接或直接的引用了自身的情况
let target = deepClone(source)
console.log('source:', source)
console.log('target:', target)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值