JS深浅拷贝

简介: 本文介绍了JavaScript中实现数据拷贝的四种方法:`Object.assign()`, 扩展运算符(`...`), `JSON.parse(JSON.stringify())` 和递归深拷贝。`Object.assign()`及扩展运算符对基本数据类型进行深拷贝,而对引用类型则进行浅拷贝。`JSON.parse(JSON.stringify())`对所有类型的数据都执行深拷贝,但存在一些限制如日期类型被转为字符串等。递归深拷贝则避免了这些问题,并支持循环引用,是一种更安全的选择。

一、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类型时,序列化之后会变成空对象{}
  • 对象中有undefined和Function类型数据的时候,序列化之后会直接丢失。
  • 对象中有NaN、Infinity和-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)
相关文章
|
JSON 前端开发 JavaScript
JavaScript拷贝大作战:浅拷贝vs深拷贝
JavaScript拷贝大作战:浅拷贝vs深拷贝
685 0
|
JSON JavaScript 前端开发
JavaScript 中更现代的深拷贝方法!
JavaScript 中更现代的深拷贝方法!
536 0
|
设计模式 存储 Java
深拷贝与浅拷贝,就是这么简单
深拷贝与浅拷贝,就是这么简单
|
JSON JavaScript 前端开发
总结JavaScript中的深拷贝与浅拷贝
总结JavaScript中的深拷贝与浅拷贝
|
前端开发 JavaScript
什么是深拷贝;深拷贝和浅拷贝有什么区别;深拷贝和浅拷贝有哪些方法(详解)
浅拷贝适用于只复制对象的第一层属性,且这些属性不是引用类型。深拷贝适用于需要完全独立的副本,包括对象和数组的嵌套结构。选择哪种拷贝方式取决于你的具体需求和场景。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
设计模式 JavaScript 算法
浅谈几种js设计模式
设计模式是软件开发中的宝贵工具,能够提高代码的可维护性和扩展性。通过单例模式、工厂模式、观察者模式和策略模式,我们可以解决不同场景下的实际问题,编写更加优雅和高效的代码。
375 8
|
缓存 自然语言处理 JavaScript
JavaScript中闭包详解+举例,闭包的各种实践场景:高级技巧与实用指南
闭包是JavaScript中不可或缺的部分,它不仅可以增强代码的可维护性,还能在模块化、回调处理等场景中发挥巨大作用。然而,闭包的强大也意味着需要谨慎使用,避免潜在的性能问题和内存泄漏。通过对闭包原理的深入理解以及在实际项目中的灵活应用,你将能够更加高效地编写出简洁且功能强大的代码。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
JavaScript 前端开发
JavaScript中的深拷贝与浅拷贝
JavaScript中的深拷贝与浅拷贝
299 4
|
JSON JavaScript 数据格式
手写JS实现深拷贝函数
本文介绍了如何实现一个深拷贝函数`deepClone`,该函数可以处理对象和数组的深拷贝,确保拷贝后的对象与原始对象在内存中互不干扰。通过递归处理对象的键值对和数组的元素,实现了深度复制,同时保留了函数类型的值和基础类型的值。
292 3
|
JavaScript 前端开发
JavaScript中的深拷贝和浅拷贝的实现讲解
在JavaScript中,浅拷贝与深拷贝用于复制对象。浅拷贝仅复制基本类型属性,对于引用类型仅复制引用,导致双方共享同一数据,一方修改会影响另一方。深拷贝则完全复制所有层级的数据,包括引用类型,确保双方独立。浅拷贝可通过简单属性赋值实现,而深拷贝需递归复制各层属性以避免共享数据。
404 1

热门文章

最新文章