前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JS 数组、对象的深拷贝

JS 数组、对象的深拷贝

原创
作者头像
Krry
发布2019-04-23 14:10:33
8.1K0
发布2019-04-23 14:10:33
举报
文章被收录于专栏:KrryblogKrryblog

博客地址:https://ainyi.com/72

JavaScript 程序中,对于简单的数字、字符串可以通过 = 赋值拷贝

但是对于数组、对象、对象数组的拷贝,就有浅拷贝和深拷贝之分

浅拷贝就是当改变了拷贝后的数据,原数据也会相应改变

来说说深拷贝

数组深拷贝

遍历赋值

不推荐此方法

let a = [1, 2, 3]
let b = []
for (let val of a) {
  b.push(val)
}
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

slice()

数组方法 slice() 可从已有的数组中返回选定的元素

那么设置为 0,就是返回整个数组

let a = [1, 2, 3]
let b = a.slice(0)
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

concat()

数组方法 concat() 连接一个或多个数组,并返回一个副本

那么不设置参数,就返回本数组

let a = [1, 2, 3]
let b = a.concat()
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

ES6 方法

let a = [1, 2, 3]
let b = [...a]
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]
let a = [1, 2, 3]
let b = Array.from(a)
b.push(4)
a // [1, 2, 3]
b // [1, 2, 3, 4]

对象深拷贝

Object.assign()

Object.assign(target, obj)

let a = { name: 'krry' }
let b = Object.assign({}, a)
b.name = 'lily'
a // { name: 'krry' }
b // { name: 'lily' }

注意使用 assign() 有如下特点:

  1. 不会拷贝对象继承的属性、不可枚举的属性、属性的数据属性/访问器属性
  2. 可以拷贝 Symbol 类型

扩展运算符

let a = { name: 'krry' }
let b = { ...a }
b.name = 'lily'
a // { name: 'krry' }
b // { name: 'lily' }

以上是简单数组、对象的深拷贝方法,但是对于二维数组、对象数组、对象里包含对象,以上方法均达不到深拷贝方法

以上只能达到数组、对象的第一层的==深拷贝==,对于里面的数组或对象属性则是==浅拷贝==,因为里面的内存地址只是拷贝了一份,但都是指向==同一个地址==

所以当改变数组、对象里的数组元素或对象,原数据依然会改变

二维数组、对象数组、多层对象的深拷贝

最常用的 JSON 序列化与反序列化

使用 JSON.parse(JSON.stringify(obj))

let a = [1, [2, {aa: 2}, [4]], {aa: 5, cc: { dd: 6 }}]
let b = JSON.parse(JSON.stringify(a)) // 完美

通过 JSON.stringify 实现深拷贝有几点要注意

  1. 拷贝的对象的值中如果有函数、undefined、symbol,则经过 JSON.stringify() 序列化后的 JSON 字符串中这个键值对会消失
  2. 无法拷贝不可枚举的属性,无法拷贝对象的原型链
  3. 拷贝 Date 引用类型会变成字符串
  4. 拷贝 RegExp 引用类型会变成空对象
  5. 对象中含有 NaN、Infinity 和 -Infinity,则序列化的结果会变成 null
  6. 无法拷贝对象的循环应用(即 objkey = obj)

自己实现深拷贝方法

function deepCopy(obj) {
  let result = Array.isArray(obj) ? [] : {};
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (typeof obj[key] === 'object') {
        result[key] = deepCopy(obj[key]);   // 递归复制
      } else {
        result[key] = obj[key];
      }
    }
  }
  return result;
}

lodash 的深拷贝 cloneDeep

使用 lodash 插件的深拷贝方法

// 官方例子
var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

传送门:https://www.lodashjs.com/docs/4.17.5.html#cloneDeep

博客地址:https://ainyi.com/72

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数组深拷贝
    • 遍历赋值
      • slice()
        • concat()
          • ES6 方法
          • 对象深拷贝
            • Object.assign()
              • 扩展运算符
              • 二维数组、对象数组、多层对象的深拷贝
                • 最常用的 JSON 序列化与反序列化
                  • 自己实现深拷贝方法
                    • lodash 的深拷贝 cloneDeep
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档