首页 > JavaScript > 复制克隆 JavaScript 对象的最有效方法是什么?obj = JSON.parse(JSON.stringify(o));

复制克隆 JavaScript 对象的最有效方法是什么?obj = JSON.parse(JSON.stringify(o));

上一篇 下一篇

网友问题:
克隆 JavaScript 对象的最有效方法是什么?我已经看到有人使用,但这是非标准的,只有Firefox支持。obj = eval(uneval(o));

我做过这样的事情,但质疑效率。obj = JSON.parse(JSON.stringify(o));

我还看到了具有各种缺陷的递归复制函数。

我很惊讶没有规范的解决方案存在。

分割线

网友回答:

查看此基准测试:http://jsben.ch/#/bWfk9

在我之前的测试中,速度是我发现的主要问题

JSON.parse(JSON.stringify(obj))

是深度克隆对象的最慢方法(它比 jQuery.extend 慢,标志设置为 true 10-20%)。deep

jQuery.extend 在标志设置为(浅克隆)时非常快。这是一个不错的选择,因为它包含一些用于类型验证的额外逻辑,并且不会复制未定义的属性等,但这也会减慢您的速度。deepfalse

如果你知道你试图克隆的对象的结构,或者可以避免深度嵌套数组,你可以编写一个简单的循环来克隆你的对象,同时检查hasOwnProperty,它将比jQuery快得多。for (var i in obj)

最后,如果您尝试在热循环中克隆已知的对象结构,则只需内联克隆过程并手动构造对象即可获得更高的性能。

JavaScript 跟踪引擎在优化循环方面很糟糕,检查 hasOwnProperty 也会减慢你的速度。当速度是绝对必要的时,手动克隆。for..in

var clonedObject = {
  knownProp: obj.knownProp,
  ..
}

当心在对象上使用该方法 – 返回 ISO 格式的日期字符串表示形式,不会转换回对象。有关更多详细信息,请参阅此答案。JSON.parse(JSON.stringify(obj))DateJSON.stringify(new Date())JSON.parse()Date

此外,请注意,至少在Chrome 65中,本机克隆不是要走的路。根据JSPerf的说法,通过创建新函数来执行本机克隆比使用JSON.stringify慢近800倍,JSON.stringify在整个方面都非常快。

ES6 更新

如果您使用的是 Javascript ES6,请尝试使用此本机方法进行克隆或浅拷贝。

Object.assign({}, obj);

分割线

网友回答:

原生深度克隆

现在有一个名为“结构化克隆”的JS标准,它在Node 11及更高版本中实验性地工作,将登陆浏览器,并且具有现有系统的polyfill。

structuredClone(value)

如果需要,请先加载填充代码:

import structuredClone from '@ungap/structured-clone';

有关更多详细信息,请参阅此答案。

较早的答案

快速克隆与数据丢失 – JSON.parse/stringify

如果你在对象中不使用s、functions、、、RegExps、Maps、Sets、Blob、FileLists、ImageDatas、稀疏数组、Typed Arrays或其他复杂类型,那么一个非常简单的深层克隆对象的行是:DateundefinedInfinity

JSON.parse(JSON.stringify(object))

const a = {
  string: 'string',
  number: 123,
  bool: false,
  nul: null,
  date: new Date(),  // stringified
  undef: undefined,  // lost
  inf: Infinity,  // forced to 'null'
  re: /.*/,  // lost
}
console.log(a);
console.log(typeof a.date);  // Date object
const clone = JSON.parse(JSON.stringify(a));
console.log(clone);
console.log(typeof clone.date);  // result of .toISOString()

请参阅 Corban 的基准测试答案。

使用库进行可靠的克隆

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

  • 洛达什 – ;可以通过 lodash.clonedeep 模块单独导入,如果您还没有使用提供深度克隆功能的库,这可能是您的最佳选择cloneDeep
  • AngularJS –angular.copy
  • j查询 – ; 仅克隆 DOM 元素jQuery.extend(true, { }, oldObject).clone()
  • 只是图书馆 – ;零依赖 npm 模块库的一部分,只做一件事。
    适合各种场合的无负罪感实用程序。just-clone

分割线

网友回答:

结构化克隆

2022 年更新:全局函数已经在Firefox 94,Node 17和Deno 1.14中可用。structuredClone

HTML 标准包括一个内部结构化克隆/序列化算法,可以创建对象的深度克隆。它仍然仅限于某些内置类型,但除了 JSON 支持的少数类型之外,它还支持日期、正则表达式、映射、集、blob、文件列表、图像数据、稀疏数组、类型数组,以及将来可能更多。它还保留克隆数据中的引用,允许它支持会导致 JSON 错误的循环和递归结构。

节点.js中的支持:

全局函数由节点 17.0 提供:structuredClone

const clone = structuredClone(original);

以前的版本:Node.js 中的模块(从 Node 11 开始)直接公开结构化序列化 API,但此功能仍标记为“实验性”,并且在将来的版本中可能会更改或删除。如果您使用的是兼容版本,则克隆对象非常简单:v8

const v8 = require('v8');

const structuredClone = obj => {
  return v8.deserialize(v8.serialize(obj));
};

浏览器中的直接支持:在 Firefox 94 中可用

全局函数将很快由所有主流浏览器提供(之前在 GitHub 上的 whatwg/html#793 中讨论过)。它看起来/将看起来像这样:structuredClone

const clone = structuredClone(original);

在发布之前,浏览器的结构化克隆实现只会间接公开。

异步解决方法:可用。?

使用现有 API 创建结构化克隆的开销较低的方法是通过 MessageChannel 的一个端口发布数据。另一个端口将发出一个事件,其中包含附加的结构化克隆。遗憾的是,侦听这些事件必然是异步的,同步替代方案不太实用。message.data

class StructuredCloner {
  constructor() {
    this.pendingClones_ = new Map();
    this.nextKey_ = 0;
    
    const channel = new MessageChannel();
    this.inPort_ = channel.port1;
    this.outPort_ = channel.port2;
    
    this.outPort_.onmessage = ({data: {key, value}}) => {
      const resolve = this.pendingClones_.get(key);
      resolve(value);
      this.pendingClones_.delete(key);
    };
    this.outPort_.start();
  }

  cloneAsync(value) {
    return new Promise(resolve => {
      const key = this.nextKey_++;
      this.pendingClones_.set(key, resolve);
      this.inPort_.postMessage({key, value});
    });
  }
}

const structuredCloneAsync = window.structuredCloneAsync =
    StructuredCloner.prototype.cloneAsync.bind(new StructuredCloner);

使用示例:

const main = async () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = await structuredCloneAsync(original);

  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

main();

同步解决方法:糟糕!?

同步创建结构化克隆没有好的选择。这里有一些不切实际的技巧。

history.pushState()并且两者都创建其第一个参数的结构化克隆,并将该值分配给 .您可以使用它来创建任何对象的结构化克隆,如下所示:history.replaceState()history.state

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

使用示例:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const oldState = history.state;
  history.replaceState(obj, null);
  const clonedObj = history.state;
  history.replaceState(oldState, null);
  return clonedObj;
};

main();

虽然是同步的,但这可能非常慢。它会产生与操作浏览器历史记录相关的所有开销。重复调用此方法可能会导致 Chrome 暂时无响应。

构造函数创建其关联数据的结构化克隆。它还会尝试向用户显示浏览器通知,但除非您已请求通知权限,否则这将以静默方式失败。如果您拥有用于其他目的的权限,我们将立即关闭我们创建的通知。Notification

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.onshow = n.close.bind(n);
  return n.data;
};

使用示例:

'use strict';

const main = () => {
  const original = { date: new Date(), number: Math.random() };
  original.self = original;

  const clone = structuredClone(original);
  
  // They're different objects:
  console.assert(original !== clone);
  console.assert(original.date !== clone.date);

  // They're cyclical:
  console.assert(original.self === original);
  console.assert(clone.self === clone);

  // They contain equivalent values:
  console.assert(original.number === clone.number);
  console.assert(Number(original.date) === Number(clone.date));
  
  console.log("Assertions complete.");
};

const structuredClone = obj => {
  const n = new Notification('', {data: obj, silent: true});
  n.close();
  return n.data;
};

main();

模板简介:该模板名称为【复制克隆 JavaScript 对象的最有效方法是什么?obj = JSON.parse(JSON.stringify(o));】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【JavaScript】栏目查找您需要的精美模板。

相关搜索
  • 下载密码 lanrenmb
  • 下载次数 796次
  • 使用软件 Sublime/Dreamweaver/HBuilder
  • 文件格式 编程语言
  • 文件大小 暂无信息
  • 上传时间 02-08
  • 作者 网友投稿
  • 肖像权 人物画像及字体仅供参考
栏目分类 更多 >
热门推荐 更多 >
单页式简历模板 微信模板 微信素材 微信公众平台 微信文章 企业网站 html5 响应式 微信图片 自适应
您可能会喜欢的其他模板