zoukankan      html  css  js  c++  java
  • (译文)JavaScript基础——JavaScript中的深拷贝

    在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);

    性能如何

    Performance in Chrome 63
    Performance in Firefox 58
    Performance in Edge 16
    结论是:
    1 如果你不处理对象依赖和内置对象,可以直接用 JSON.parse(JSON.stringify())

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

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

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

  • 相关阅读:
    学习笔记2-查看目录文件
    学习笔记1-基本信息及相关目录
    【图论】二分图最大匹配
    【图论】Dinic算法
    【图论】最小割
    【数据结构】左偏树
    【数学】欧拉定理
    【数据结构】ST表
    【数学】博弈模型
    【字符串】后缀数组
  • 原文地址:https://www.cnblogs.com/xunxing/p/a255ce21d8d85939ec4ce56def8cc0b0.html
Copyright © 2011-2022 走看看