Code前端首页关于Code前端联系我们

js中对象深拷贝方法总结

terry 2年前 (2023-09-09) 阅读数 174 #Javascript

js深拷贝的问题在实际工作和面试中经常会用到。

有些公司经常需要原生手写实现:(这篇文章我也会介绍一个简单的原生实现。

但是我不认为自己写的兼容性和适用性可以和别人的框架相比。

js中对象深拷贝方法总结

快速克隆(存在数据丢失问题) – JSON.parse/stringify

如果您在对象中不使用 Date、functions、undefined、Infinity、RegExps、Maps、Sets、blob、FileLists、ImageDatas 或其他复杂类型,则只需一行即可轻松深度克隆对象库代码。

简单来说,有以下几个问题:

  • 忽略undefined
  • 忽略symbol
  • 无法序列化函数
  • 无法解析具有循环引用的对象
JSON.parse(JSON.stringify(object))
const a = {
  string:‘string’,
  数量:123,
  布尔:假,
  nul:null,
  date: new Date(), // string化
  undef: 未定义, // 丢失
  inf: Infinity, // 强制进入“nul”
  回复:/.*/,//丢失
}
控制台.log(a);
console.log(a.date的类型); // 日期对象
const 克隆 = JSON.parse(JSON.stringify(a));
控制台.log(克隆);
console.log(类型克隆.date); // .toISOString() 的结果

使用第三方框架

由于克隆对象并不容易(复杂类型、循环引用、函数等),所以大多数主流库都提供了克隆对象的功能。 不要重新发明轮子 - 如果您已经在使用库,请检查它是否具有对象克隆功能。例如:

  • 洛达什cloneDeep;可以通过 lodash.cloneDeep 模块单独导入。如果你之前没有使用过lodash,那么lodash是一个非常好的选择。
  • AngularJS angular.copy
  • jQuery – jQuery.extend(true, { }, oldObject).clone() 只能克隆 DOM

ES6

为了完整起见,请注意 ES6 提供了两种表面复制机制:Object.assign() 和扩展运算符语法。它将所有可枚举自属性的值从一个对象复制到另一个对象。例如:

var A1 = {a: "2"};
var A2 = Object.assign({}, A1);
var A3 = {...A1}; // 扩展运算符

深度复制的本机实现

原生手写深拷贝代码是面试中经常遇到的。虽然在实际项目开发中不太常用,但大家还是应该熟练掌握手写代码的思想,因为它经常在真实的面试中得到检验~

function deepClone(obj) {
  function isObject(o) {
    return (typeof o === 'object' || typeof o === 'function') && o !== null
  }

  if (!isObject(obj)) {
    throw new Error('非对象')
  }

  let isArray = Array.isArray(obj)
  let newObj = isArray ? [...obj] : { ...obj }
  Reflect.ownKeys(newObj).forEach(key => {
    newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
  })

  return newObj
}

let obj = {
  a: [1, 2, 3],
  b: {
    c: 2,
    d: 3
  }
}
let newObj = deepClone(obj)
newObj.b.c = 1
console.log(obj.b.c) // 2

留言频道

MessageChannel也是一种实现深拷贝的方式。

function structuralClone(obj) {
  return new Promise(resolve => {
    const { port1, port2 } = new MessageChannel()
    port2.onmessage = ev => resolve(ev.data)
    port1.postMessage(obj)
  })
}

var obj = {
  a: 1,
  b: {
    c: 2
  }
}

obj.b.d = obj.b

// 注意该方法是异步的
// 可以处理 undefined 和循环引用对象
const test = async () => {
  const clone = await structuralClone(obj)
  console.log(clone)
}
test()

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门