JavaScript 深浅拷贝其实没那么难

发布于 2023-05-12 12:40:17 字数 3483 浏览 68 评论 0

什么是深浅拷贝?

  • 浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

  • 深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

浅拷贝的几种方式

array.slice()array.concat()Object.assign() 都能实现浅拷贝,前两个针对数组。还可以用以下这种方式。

// 浅拷贝
function shallowCopy(source, target = {}) {
  for (let key in source) {
    if (source.hasOwnProperty(key)) {
      target[key] = source[key]
    }
  }
  return target
}

let student1 = {
  name: 'Frankie',
  age: 22,
  language: ['Chinese', ['English', 'German']]
}

let student2 = shallowCopy(student1)
student2.language[1] = ['French']

console.log(student1)
console.log(student2)
// 打印对比可知,language 同时改变了

深拷贝的几种方式

JSON

利用 JSON.stringify & JSON.parse 方法

不足:

  1. 无法拷贝对象中的方法属性;
  2. 无法拷贝对象中的 undefined 属性

JQuery

JQuery 提供的两种方法 $.extend()$.clone() ,前者是 JS 对象的拷贝、后者是 DOM 对象的拷贝(这里不讨论)

不足:

  1. 需要引入 JQuery 库
  2. 无法拷贝对象中的 undefined 属性

递归

利用 for..in..hasOwnProperty递归实现

不足:比上面的两种方式稍复杂

递归实现深拷贝:

// 假设在 Object 的原型,添加一个 height 属性
Object.prototype.height = 180

// student1 什么类型的属性都有了
const student1 = {
  name: 'Frankie',
  age: 22,
  private: true,
  friends: ['Mandy', 'John'],
  abilities: undefined,
  other: null,
  car: {
    color: 'gray',
    brand: 'Benz'
  },
  teacher: {
    name: 'Ada',
    student: ['Helkai', 'Jerry']
  },
  learn: function () {
    console.log(this.name + ' is learning JavaScript now.')
  }
}

// 深拷贝
function deepCopy(source, target = {}) {
  for (const key in source) {
    // for...in... 会遍历原型链上的属性,所以这里需要利用 hasOwnProperty 判断,否则会把 Object 原型上的 height 也拷贝进去了
    if (source.hasOwnProperty(key)) {
      if (typeof source[key] === 'object' && source[key] !== null) {
        // 判断是否为数组
        target[key] = Object.prototype.toString.call(source[key]) === '[object Array]' ? [] : {}
        // 递归
        deepCopy(source[key], target[key])
      } else {
        target[key] = source[key]
      }
    }
  }
  return target
}

// 从 student1 中拷贝一个 student2 出来
const student2 = deepCopy(student1)
// 修改 student2 的属性值
student2.name = 'Steven'
student2.age = 20
student2.car = {
  color: 'red',
  brand: 'BMW'
}
student2.friends[1] = 'Jone'
student2.teacher.age = '30'
// 打印结果看下面截图,结果是没有相互影响的
console.log(student1)
console.log(student2)

// JSON 方式
const student3 = JSON.parse(JSON.stringify(student1))
console.log(student3) //  打印 student3 可见 abilities、learn 属性丢失了

运行结果

日常搬砖选择哪种方式呢,视具体情况而定。我的话,能用 JSON 方式解决的,绝不用递归,没必要复杂化,简单够用即可。但是学习的话,递归的方式必须得懂啊,其实不难懂。其实还有优化的空间,我们都知道 for...in 的性能是比较差的。关于性能优化篇,可以看下掘金某大神的文章,这里

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

痴骨ら

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

亽野灬性zι浪

文章 0 评论 0

少年亿悲伤

文章 0 评论 0

南七夏

文章 0 评论 0

qq_EJoXxu

文章 0 评论 0

17780639550

文章 0 评论 0

萌逼全场

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文