如何在 JavaScript 中克隆对象数组?

Posted

技术标签:

【中文标题】如何在 JavaScript 中克隆对象数组?【英文标题】:How do you clone an array of objects in JavaScript? 【发布时间】:2010-10-10 12:01:47 【问题描述】:

...每个对象还具有对同一数组中其他对象的引用?

当我第一次想到这个问题时,我只是想到了类似的东西

var clonedNodesArray = nodesArray.clone()

将存在并搜索有关如何在 javascript 中克隆对象的信息。我确实在 *** 上找到了a question(由相同的@JohnResig 回答),他指出使用 jQuery 你可以做到

var clonedNodesArray = jQuery.extend(, nodesArray);

克隆一个对象。不过我试过了,这只复制了数组中对象的引用。所以如果我

nodesArray[0].value = "red"
clonedNodesArray[0].value = "green"

nodesArray[0] 和 clonedNodesArray[0] 的值都会变成“绿色”。然后我尝试了

var clonedNodesArray = jQuery.extend(true, , nodesArray);

它深度复制了一个对象,但我分别从Firebug 和Opera Dragonfly 收到了“太多递归”和“控制堆栈溢出”消息。

你会怎么做?这是不应该做的事情吗?在 JavaScript 中是否有可重用的方法?

【问题讨论】:

What is the most efficient way to deep clone an object in JavaScript? 【参考方案1】:

我想我设法编写了一个通用方法来深度克隆任何 JavaScript 结构,主要使用所有现代浏览器都支持的Object.create。代码是这样的:

function deepClone (item) 
  if (Array.isArray(item)) 
    var newArr = [];

    for (var i = item.length; i-- !== 0;) 
      newArr[i] = deepClone(item[i]);
    

    return newArr;
  
  else if (typeof item === 'function') 
    eval('var temp = '+ item.toString());
    return temp;
  
  else if (typeof item === 'object')
    return Object.create(item);
  else
    return item;

【讨论】:

Object.create 会将item 视为对象的原型,但这与克隆不同。如果修改了item,则更改将反映在其“克隆”中,反之亦然。这种方法行不通。【参考方案2】:

对于克隆对象,我只是建议 ECMAScript 6 reduce():

const newArray = myArray.reduce((array, element) => array.push(Object.assign(, element)), []);

但坦率地说,我更喜欢the answer of dinodsaurus。我只是把这个版本作为另一种选择,但我个人将按照 dinodsaurus 的建议使用map()

【讨论】:

【参考方案3】:

根据您是否拥有Underscore.js 或Babel,这里是深度克隆数组的不同方法的基准。

https://jsperf.com/object-rest-spread-vs-clone/2

看来 Babel 是最快的。

var x = babel(, obj)

【讨论】:

【参考方案4】:
var game_popularity = [
      game: "fruit ninja", popularity: 78 ,
      game: "road runner", popularity: 20 ,
      game: "maze runner", popularity: 40 ,
      game: "ludo", popularity: 75 ,
      game: "temple runner", popularity: 86 
];
console.log("sorted original array before clonning");
game_popularity.sort((a, b) => a.popularity < b.popularity);
console.log(game_popularity);


console.log("clone using object assign");
const cl2 = game_popularity.map(a => Object.assign(, a));
cl2[1].game = "*** of titan";
cl2.push( game: "logan", popularity: 57 );
console.log(cl2);


// Adding new array element doesnt reflect in original array
console.log("clone using concat");
var ph = []
var cl = ph.concat(game_popularity);

// Copied by reference ?
cl[0].game = "rise of civilization";

game_popularity[0].game = 'ping me';
cl.push( game: "angry bird", popularity: 67 );
console.log(cl);

console.log("clone using ellipses");
var cl3 = [...game_popularity];
cl3.push( game: "blue whale", popularity: 67 );
cl3[2].game = "harry potter";
console.log(cl3);

console.log("clone using json.parse");
var cl4 = JSON.parse(JSON.stringify(game_popularity));
cl4.push( game: "home alone", popularity: 87 );
cl4[3].game ="lockhead martin";
console.log(cl4);

console.log("clone using Object.create");
var cl5 = Array.from(Object.create(game_popularity));
cl5.push( game: "fish ville", popularity: 87 );
cl5[3].game ="veto power";
console.log(cl5);


// Array function
console.log("sorted original array after clonning");
game_popularity.sort((a, b) => a.popularity < b.popularity);
console.log(game_popularity);


console.log("Object.assign deep clone object array");
console.log("json.parse deep clone object array");
console.log("concat does not deep clone object array");
console.log("ellipses does not deep clone object array");
console.log("Object.create does not deep clone object array");

输出

sorted original array before clonning
[  game: 'temple runner', popularity: 86 ,
 game: 'fruit ninja', popularity: 78 ,
 game: 'ludo', popularity: 75 ,
 game: 'maze runner', popularity: 40 ,
 game: 'road runner', popularity: 20  ]
clone using object assign
[  game: 'temple runner', popularity: 86 ,
 game: '*** of titan', popularity: 78 ,
 game: 'ludo', popularity: 75 ,
 game: 'maze runner', popularity: 40 ,
 game: 'road runner', popularity: 20 ,
 game: 'logan', popularity: 57  ]
clone using concat
[  game: 'ping me', popularity: 86 ,
 game: 'fruit ninja', popularity: 78 ,
 game: 'ludo', popularity: 75 ,
 game: 'maze runner', popularity: 40 ,
 game: 'road runner', popularity: 20 ,
 game: 'angry bird', popularity: 67  ]
clone using ellipses
[  game: 'ping me', popularity: 86 ,
 game: 'fruit ninja', popularity: 78 ,
 game: 'harry potter', popularity: 75 ,
 game: 'maze runner', popularity: 40 ,
 game: 'road runner', popularity: 20 ,
 game: 'blue whale', popularity: 67  ]
clone using json.parse
[  game: 'ping me', popularity: 86 ,
 game: 'fruit ninja', popularity: 78 ,
 game: 'harry potter', popularity: 75 ,
 game: 'lockhead martin', popularity: 40 ,
 game: 'road runner', popularity: 20 ,
 game: 'home alone', popularity: 87  ]
clone using Object.create
[  game: 'ping me', popularity: 86 ,
 game: 'fruit ninja', popularity: 78 ,
 game: 'harry potter', popularity: 75 ,
 game: 'veto power', popularity: 40 ,
 game: 'road runner', popularity: 20 ,
 game: 'fish ville', popularity: 87  ]
sorted original array after clonning
[  game: 'ping me', popularity: 86 ,
 game: 'fruit ninja', popularity: 78 ,
 game: 'harry potter', popularity: 75 ,
 game: 'veto power', popularity: 40 ,
 game: 'road runner', popularity: 20  ]

Object.assign deep clone object array
json.parse deep clone object array
concat does not deep clone object array
ellipses does not deep clone object array
Object.create does not deep clone object array

【讨论】:

【参考方案5】:

浅拷贝最简洁的解决方案:

array = array.map(obj => 
    return  ...obj ;
);

这将创建一个完全独立的副本,例如 [a: 1, b: 2],但不是 [a: b: 2, b: a: 1]

【讨论】:

以上是关于如何在 JavaScript 中克隆对象数组?的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript JavaScript克隆对象和数组

如何在 PHP 中克隆对象数组?

JavaScript克隆对象和数组

JS----对象的合并与克隆与数组的深浅克隆

具有属性子集的对象数组克隆

在 JavaScript 中克隆对象