在JavaScript中如何拷贝一个对象?

通过引用调用

function mutate(obj) {
obj.a = true;
}
const obj = {a: false};
mutate(obj)
console.log(obj.a); // prints true

mutate可以对obj进行改动,然后外面的obj的值也变化了。

浅拷贝:Object.assign()

一种拷贝方式是这种方法: Object.assign(target, sources...).

const obj = /* ... */;
const copy = Object.assign({}, obj);

但是这种拷贝只是浅拷贝:

function mutateDeepObject(obj) {
obj.a.thing = true;
}
const obj = {a: {thing: false}};
const copy = Object.assign({}, obj);
mutateDeepObject(copy)
console.log(obj.a.thing); // prints true

JSON.parse

通过转换为字符串,然后再转回来:

const obj = /* ... */;
const copy = JSON.parse(JSON.stringify(obj));

这样不好的地方是你会处理一个大的字符串,并且无法处理

循环对象:

const x = {};
const y = {x};
x.y = y; // Cycle: x.y.x.y.x.y.x.y.x...
const copy = JSON.parse(JSON.stringify(x)); // throws!

而且像Maps, Sets, RegExps, Dates, ArrayBuffers和其他内置对象序列化的时候可能都有问题。

结构化克隆

它是一种算法,将一个值转换为另外一个值。而且能处理对象循环依赖和大部分的内置对象。比如调用postMessage发消息给window或者WebWorker的时候就用到。

比如像这样:obj是被深拷贝过的

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

历史API

如果你用过history.pushState()去构建一个单页应用(SPA),你应该知道你可以根据当前URL保存一个state object。这个state object是结构化拷贝的,并且是同步的。

function structuralClone(obj) {
const oldState = history.state;
history.replaceState(obj, document.title);
const copy = history.state;
history.replaceState(oldState, document.title);
return copy;
}
const obj = /* ... */;
const clone = structuralClone(obj);

不好的地方是Safari限制replaceState的调用次数。

通知API

function structuralClone(obj) {
return new Notification('', {data: obj, silent: true}).data;
}
const obj = /* ... */;
const clone = structuralClone(obj);

性能如何







结论是:

1 如果你不处理对象依赖和内置对象,可以直接用 JSON.parse(JSON.stringify())

2 如果你要可靠的跨浏览器支持:用MessageChannel

原文:

https://dassur.ma/things/deep-copy/#call-by-reference

作者知乎/公众号:前端疯

(译文)JavaScript基础——JavaScript中的深拷贝的更多相关文章

  1. JavaScript基础——JavaScript入门(笔记)

    JavaScript入门(笔记) JavaScript是一种轻量级.解释型的Web开发语言,该语言系统不是很庞杂,简单易学.由于所有现代浏览器都已嵌入JavaScript引擎,JavaScript源代 ...

  2. Javascript基础 - js中曾经忽略的知识点

    深入那些曾经忽略的Javascript知识 1. parseInt(string, [radix]),parseFloat(string) 一般我们省略第二个参数,parseInt(‘100’) == ...

  3. JavaScript基础内容中的函数详解

    函数 函数:即方法 函数就是一段预先设置的功能代码块,可以反复调用,根据输入参数的不同,返回不同的值. 为什么使用函数: 1.方便调用 2.代码重用,利于维护 3.便于修改,便于重构 4.简化逻辑,利 ...

  4. JavaScript基础函数体中的唯一var模式(002)

    全局变量是不好的.所以在声名变量的时候,应该采用函数体中的唯一var模式(Single var Pattern).这个模式有不少好处: 提供了一个唯一的地方来查看函数体中声名的变量 在使用一个变量之前 ...

  5. JavaScript基础Javascript中的循环(003)

    1.普通循环JavaScript中一般的循环写法是这样的: // sub-optimal loop for (var i = 0; i < myarray.length; i++) { // d ...

  6. JavaScript基础——JavaScript语法基础(笔记)

    JavaScript语法基础(笔记) 1.语言编码 JavaScript语言建立在Unicode字符集基础之上,因此脚本中,用户可以使用双字节的字符命名常量.变量或函数等. [示例] var 我=&q ...

  7. JavaScript基础——JavaScript函数(笔记)

    avaScript 函数(笔记) JavaScript 是函数式编程语言,在JavaScript脚本中可以随处看到函数,函数构成了JavaScript源代码的主体. 一.定义函数 定义函数的方法有两种 ...

  8. JavaScript基础——JavaScript常量和变量(笔记)

    JavaScript常量和变量(笔记) Javascript代码严格区分大小写. javascript暂不支持constant关键字,不允许用户自定义常量. javascript使用var关键字声明变 ...

  9. JavaScript基础JavaScript的常用编码惯例(007)

    采用一定的编码惯例,可以使得项目中的代码提到较高的一致性,可读性和可预测性. 1.缩进缩 进可以提高代码的可读性.不过错误的缩进也可能导致代码的误读.有人认为缩进应该使用tab,另外的一些人主张采用4 ...

随机推荐

  1. Linux显示按文件大小降序排列

    Linux显示按文件大小降序排列 youhaidong@youhaidong-ThinkPad-Edge-E545:~$ ls -ls 总用量 56 12 -rw-r--r-- 1 youhaidon ...

  2. Good Bye 2017 E. New Year and Entity Enumeration

    先按照绿点进行分块 第一个绿点和最后一个绿点之后很好处理不说了 两个绿点之间的讨论: 有两种方案 1:红(蓝)点和绿点顺序连接,距离为相邻绿点距离(也就是双倍绿点距离) 2:红(蓝)点和绿点的点阵中寻 ...

  3. httpclient案例一(调用识别接口)

    public Map<String, Object> pictureRecognition(String recotype, MultipartFile imageFile) { Stri ...

  4. freemarker声明变量(十)

    freemarker声明变量 1.使用assign创建和替换变量 (1)新建声明变量的ftl variable.ftl: <html> <head> <meta http ...

  5. freemarker之include指令(九)

    freemarker之include指令 1.父页面ftl <html> <head> <meta http-equiv="content-type" ...

  6. Keras常见问题及解答

    Keras官方中文版文档 如何引用 Keras? 如何在 GPU 上运行 Keras? 如何在多 GPU 上运行 Keras 模型? "sample", "batch&q ...

  7. Bzoj3992:[SDOI2015]序列统计

    题面 Bzoj Sol pts 1 大暴力很简单,\(f[i][j]\)表示到第\(i\)个位置,前面积的模为\(j\)的方案 然后可以获得\(10\)分的好成绩 # include <bits ...

  8. [APIO2009]抢掠计划

    题面: Description Siruseri城中的道路都是单向的.不同的道路由路口连接.按照法律的规定,在每个路口都设立了一个Siruseri银行的ATM取款机.令人奇怪的是,Siruseri的酒 ...

  9. 基于Redis的简单分布式锁的原理

    参考资料:https://redis.io/commands/setnx 加锁是为了解决多线程的资源共享问题.Java中,单机环境的锁可以用synchronized和Lock,其他语言也都应该有自己的 ...

  10. javaScript数组操作整理

    一.js数组 1.创建数组: var arr = new Array();//创建没有元素空数组 var arr1 = new Array("value1","valeu ...