我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
当前回答
我认为有一个简单有效的答案。在深度复制中,有两个问题:
保持财产相互独立。并在克隆的对象上保持方法的有效性。
所以我认为一个简单的解决方案是首先序列化和反序列化,然后对其进行赋值以复制函数。
let deepCloned = JSON.parse(JSON.stringify(source));
let merged = Object.assign({}, source);
Object.assign(merged, deepCloned);
虽然这个问题有很多答案,但我希望这个问题也能有所帮助。
其他回答
结构化克隆
2022年更新:structuredClone()全局函数已在Node 17、Deno 1.14和大多数主要浏览器中可用(请参阅我可以使用)。
您可以使用与HTML标准相同的结构化克隆机制在领域之间发送数据。
const clone = structuredClone(original);
有关详细信息,请参阅另一个答案。
如果在对象中不使用Dates、functions、undefined、regExp或Infinity,那么一个非常简单的一行代码就是JSON.parse(JSON.stringify(object)):
常量a={string:'字符串',编号:123,bool:false,nul:空,date:new date(),//字符串化undef:未定义,//丢失inf:无限,//强制为“null”}控制台日志(a);console.log(类型a.date);//日期对象constclone=JSON.parse(JSON.stringify(a));console.log(克隆);console.log(clone.date的类型);//.toISOString()的结果
这适用于包含对象、数组、字符串、布尔值和数字的所有类型的对象。
另请参阅本文,了解浏览器的结构化克隆算法,该算法在向工作人员发布消息时使用。它还包含一个用于深度克隆的功能。
如果对象中没有循环依赖关系,我建议使用其他答案之一或jQuery的复制方法,因为它们看起来都很有效。
如果存在循环依赖关系(即,两个子对象彼此链接),那么你就有点糟糕了,因为(从理论角度)没有办法优雅地解决这个问题。
如果你对一个浅拷贝没有问题,underscore.js库有一个克隆方法。
y = _.clone(x);
或者你可以像
copiedObject = _.extend({},originalObject);
我已经编写了自己的实现。不确定它是否算作更好的解决方案:
/*
a function for deep cloning objects that contains other nested objects and circular structures.
objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
index (z)
|
|
|
|
|
| depth (x)
|_ _ _ _ _ _ _ _ _ _ _ _
/_/_/_/_/_/_/_/_/_/
/_/_/_/_/_/_/_/_/_/
/_/_/_/_/_/_/...../
/................./
/..... /
/ /
/------------------
object length (y) /
*/
实施情况如下:
function deepClone(obj) {
var depth = -1;
var arr = [];
return clone(obj, arr, depth);
}
/**
*
* @param obj source object
* @param arr 3D array to store the references to objects
* @param depth depth of the current object relative to the passed 'obj'
* @returns {*}
*/
function clone(obj, arr, depth){
if (typeof obj !== "object") {
return obj;
}
var length = Object.keys(obj).length; // native method to get the number of properties in 'obj'
var result = Object.create(Object.getPrototypeOf(obj)); // inherit the prototype of the original object
if(result instanceof Array){
result.length = length;
}
depth++; // depth is increased because we entered an object here
arr[depth] = []; // this is the x-axis, each index here is the depth
arr[depth][length] = []; // this is the y-axis, each index is the length of the object (aka number of props)
// start the depth at current and go down, cyclic structures won't form on depths more than the current one
for(var x = depth; x >= 0; x--){
// loop only if the array at this depth and length already have elements
if(arr[x][length]){
for(var index = 0; index < arr[x][length].length; index++){
if(obj === arr[x][length][index]){
return obj;
}
}
}
}
arr[depth][length].push(obj); // store the object in the array at the current depth and length
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) result[prop] = clone(obj[prop], arr, depth);
}
return result;
}