什么是最有效的方式来克隆一个JavaScript对象?我已经看到obj = eval(uneval(o));被使用,但它是非标准的,仅支持Firefox.我做了事情,如obj = JSON.parse(JSON.stringify(o));但质疑效率。


当前回答

没有触摸原型遗产,你可以如下深孤独的物体和岩石;

函数 objectClone(o){ var ot = Array.isArray(o); return o!== null && typeof o === “object”? Object.keys(o).reduce((r,k) => o[k]!== null && typeof o[k] === “object”? (r[k] = objectClone(o[k]),r) : (r[k] = o[k],r), ot?

其他回答

如果您正在使用它,UnderScore.js图书馆有一个克隆方法。

var newObject = _.clone(oldObject);

对于清晰的旧的JavaScript对象,在现代运行时间中克隆对象的一种尝试和真正的好方法是简单的:

var clone = JSON.parse(JSON.stringify(obj));

现在,对于非清晰的JavaScript对象,没有一个真正简单的答案。 事实上,它不能因为JavaScript功能的动态性质和内部对象状态。 深度克隆一个JSON结构与内部功能需要你重建这些功能和它们的内部背景。

我们写了自己的,但我见过的最佳通用方法在这里覆盖:

首頁 〉外文書 〉文學 〉文學 〉 http://davidwalsh.name/javascript-clone

这是有效的吗? Heck 是的. 因为目标是产生一个真正的深复制克隆,那么你将不得不走路的成员的来源对象图。

所以你去吧!两个方法,我认为两者都是有效的。

我通常使用 var newObj = JSON.parse( JSON.stringify(oldObje) );但是,这里有一个更合适的方式:

var o = {};

var oo = Object.create(o);

(o === oo); // => false

观看遗传浏览器!

结构化克隆

HTML 标准包含一个内部结构化的克隆/序列化算法,可以创建对象的深度克隆,它仍然仅限于某些内置类型,但除了由 JSON 支持的少数类型之外,它还支持日期、RegExps、地图、套件、Blobs、FileLists、ImageDatas、Sparse Arrays、Typed Arrays等。

结构化Clone 全球功能由 Node 17.0 提供:

const clone = structuredClone(original);

以前版本: Node.js 的 v8 模块(如 Node 11 )直接展示了结构化序列化 API,但此功能仍然被标记为“实验性”,并在未来的版本中可更改或删除。

const v8 = require('v8');

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

直接支持浏览器:可用于Firefox 94

const clone = structuredClone(original);

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

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

雖然同步,但這可能非常慢。 它發生了所有與操縱瀏覽器歷史相關的頭部. 重複召喚這種方法可能會導致Chrome暫時變成無責任。

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

使用 Object.create() 获取原型和支持的例子,并使用 for() 圈获取可列的密钥:

function cloneObject(source) {
    var key,value;
    var clone = Object.create(source);

    for (key in source) {
        if (source.hasOwnProperty(key) === true) {
            value = source[key];

            if (value!==null && typeof value==="object") {
                clone[key] = cloneObject(value);
            } else {
                clone[key] = value;
            }
        }
    }

    return clone;
}