我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
当前回答
您可以简单地使用扩展属性来复制没有引用的对象。但是要小心(请参见注释),“副本”仅位于最低的对象/数组级别。嵌套的财产仍然是引用!
完整克隆:
let x = {a: 'value1'}
let x2 = {...x}
// => mutate without references:
x2.a = 'value2'
console.log(x.a) // => 'value1'
在第二级克隆引用:
const y = {a: {b: 'value3'}}
const y2 = {...y}
// => nested object is still a references:
y2.a.b = 'value4'
console.log(y.a.b) // => 'value4'
JavaScript实际上不支持本地深度克隆。使用效用函数。例如Ramda:
http://ramdajs.com/docs/#clone
其他回答
这里许多同行针对深度克隆提出的解决方案JSON.parse(JSON.stringify(orig_obj)有几个问题,我发现这些问题如下:
它在复制原始对象中未定义值的条目时丢弃这些条目,如果有一些值,如Infinity、NaN等,它们将在复制时转换为null,如果原始对象中存在Date类型,则它将在克隆对象中字符串化(typeof Date_entry-->string)。
找到了一种克隆对象的有效方法,它在各种场景中都很适合我。请看一看下面的代码,因为它已经解决了JSON.parse(…)的所有上述缺陷,但最终实现了正确的深度克隆:
var orig_obj = {
string: 'my_str',
number: 123,
bool: false,
nul: null,
nested : {
value : true
},
nan : NaN,
date: new Date(),
undef: undefined,
inf: Infinity,
}
console.log("original_obj before modification: ", orig_obj, "\n");
console.log(typeof orig_obj.date, "\n");
var clone_obj = Object.assign({}, orig_obj);
//this below loop will help in deep cloning and solving above issues
for(let prop in orig_obj) {
if(typeof orig_obj[prop] === "object") {
if(orig_obj[prop] instanceof Date)
clone_obj[prop] = orig_obj[prop];
else {
clone_obj[prop] = JSON.parse(JSON.stringify(orig_obj[prop]));
}
}
}
console.log("cloned_obj before modification: ", orig_obj, "\n");
clone_obj.bool = true;
clone_obj.nested.value = "false";
console.log("original_obj post modification: ", orig_obj, "\n");
console.log("cloned_obj post modification: ", clone_obj, "\n");
console.log(typeof clone_obj.date);
使用(…)复制对象
//bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2,c: 3 }
//good
const originalObj = { id: 5, name: 'San Francisco'};
const copyObject = {...originalObj, pincode: 4444};
console.log(copyObject) //{ id: 5, name: 'San Francisco', pincode: 4444 }
同样可以用于将阵列从一个复制到另一个
const itemsCopy = [...items];
本机JS:
const shallowClone = {...originalObj};
const deepClone = JSON.parse(JSON.stringify(originalObj));
使用库:
// Lodash
const shallowClone = _.clone(originalObj);
const deepClone = _. cloneDeep(originalObj);
// JQuery
const shallowClone = jQuery.extend({}, originalObj);
const deepClone = jQuery.extend(true, {}, originalObj);
// Angular
const deepClone = angular.copy(originalObj);
我之所以来到这个页面是因为同样的问题,但我既没有使用JQuery,也没有一个克隆方法适用于我自己的对象。
我知道我的答案与这个问题没有太大关系,因为这是一种不同的方法。我不使用克隆函数,而是使用创建函数。它对我来说有以下(不幸的是限制)目的:
我主要使用JSP生成的Javascript我一开始就知道必须生成哪个Object(在我的例子中,它是来自数据库的信息,只获取一次,需要在JS中更频繁地部署。
首先,我这样定义对象:
var obj= new Object();
obj.Type='Row';
obj.ID=1;
obj.Value='Blah blah';
现在我移动了所有的东西,比如:
function getObjSelektor(id_nummer,selected){
var obj = document.createElement("select");
obj.setAttribute("id","Selektor_"+id_nummer);
obj.setAttribute("name","Selektor");
obj.setAttribute("size","1");
var obj_opt_1 = document.createElement("option");
obj_opt_1.setAttribute("value","1");
if(1==selected)
posopval_opt_1.setAttribute("selected","selected");
obj_opt_1.innerHTML="Blah blah";
obj.appendChild(obj_opt_1);
var obj_opt_2 = document.createElement("option");
obj_opt_2.setAttribute("value","2");
if(2==selected)
obj_opt_2.setAttribute("selected","selected");
obj_opt_2.innerHTML="2nd Row";
obj.appendChild(obj_opt_2);
...
return obj;
}
并调用常规代码中的函数:
myDiv.getObjSelektor(getObjSelektor(anotherObject.ID));
正如所说,这是一种不同的方法,它为我的目的解决了我的问题。
在ECMAScript 6中有Object.assign方法,它将所有可枚举自身财产的值从一个对象复制到另一个对象。例如:
var x = {myProp: "value"};
var y = Object.assign({}, x);
但请注意,这是一个浅层复制-嵌套对象仍然作为引用复制。