前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手动封装对象深拷贝方法

手动封装对象深拷贝方法

作者头像
用户9914333
发布2022-07-21 19:21:30
6520
发布2022-07-21 19:21:30
举报
文章被收录于专栏:bug收集bug收集

项目中,我们经常需要对对象进行深拷贝。 我们一般想到的方法是使用JSON.stringify(sourceObj),此方法将对象转成字符串,在使用 JSON.parse(jsonTarget)将字符串转对象。

可以通过上面的方法实现对象的深拷贝。

JSON.parse 和 JSON.stringify 会出现转换属性值前后的不一致性

  • 函数无法序列化函数,属性值为函数的属性转换之后丢失
  • 日期 Date 对象javascript Date 对象转换到 JSON 对象之后无法反解析为 原对象类型,解析后的值仍然是 JSON 格式的字符串
  • 正则 RegExp 对象RegExp 对象序列化后为一个普通的 javascript 对象,同样不符合预期
  • undefined序列化之后直接被过滤掉,丢失拷贝的属性
  • NaN序列化之后为 null,同样不符合预期结果

此方式拷贝对象因为有以上这么多缺陷,所以我们不如自己封装一个属于自己的 javascript 对象深拷贝的函数,反而一劳永逸

手动封装对象深拷贝方法

对象属性的拷贝无疑就是把源对象的属性以深度遍历的方式复制到新的对象上,当遍历到一个属性值为对象类型的值时,就需要针对这个值进行再次的遍历,也是就用递归的方式遍历源对象的所有属性。让我们先看这一部分代码

代码语言:javascript
复制
function cloneDeep(obj) {const result = {}for (let key in obj) {// 判断key 是否是对象自身上的属性,以避免对象原型链上属性的拷贝if (obj.hasOwnProperty(key)) {      result[key] = cloneDeep(obj[key]) //需要对属性值递归拷贝    }  }}

这段代码是对象属性深拷贝的逻辑,但是不同的数据类型各自有其特殊的操作方式需要处理,下面就把这些处理边界场景的代码补充上,看看完成的代码应该是怎样的

代码语言:javascript
复制
function isPrimitiveValue(value) {
if (
typeof value === 'string' ||
typeof value === 'number' ||
value == null ||
typeof value === 'boolean' ||
    Number.isNaN(value)
  ) {
return true
  }
return false
}
function cloneDeep(value) {
// 判断拷贝的数据类型,如果为原始类型数据,直接返回其值
if (isPrimitiveValue(value)) {
return value
  }
// 定义一个保存引用类型的变量,根据 引用数据类型不同的子类型初始化不同的值,以下对象类型的判断和初始化可以根据自身功能的需要做删减。这里列出了所有的引用类型的场景。
let result
if (typeof value === 'function') {
// result=value 如果复制函数的时候需要保持同一个引用可以省去新函数的创建,这里用eval创建了一个原函数的副本
    result = eval(`(${value.toString()})`)
  } else if (Array.isArray(value)) {
    result = []
  } else if (value instanceof RegExp) {
    result = new RegExp(value)
  } else if (value instanceof Date) {
    result = new Date(value)
  } else if (value instanceof Number) {
    result = new Number(value)
  } else if (value instanceof String) {
    result = new String(value)
  } else if (value instanceof Boolean) {
    result = new Boolean(value)
  } else if (typeof value === 'object') {
    result = new Object()
  }
for (let key in value) {
if (value.hasOwnProperty(key)) {
try {
        result[key] = cloneObject(value[key]) //属性值为原始类型包装对象的时候,(Number,String,Boolean)这里会抛错,需要加一个错误处理,对运行结果没有影响。
      } catch (error) {
// console.error(error)
      }
    }
  }
return result
}

代码中首先封装了一个判断数据是否是原始类型的方法,这里只是为了保持 cloneDeep 函数的功能干净,其实你也可以完全放到一块,这个完全取决于自己的编码风格。如果在业务上需要有多处判断数据是原始类型还是引用类型的场景时,以上这种代码功能抽离的方式就方便处理了 参考:https://juejin.im/post/5e892e0251882573ba207c2e

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-04-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 bug收集 微信公众号,前往查看

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

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档