我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
我有一个对象x。我想将其复制为对象y,这样对y的更改不会修改x。我意识到复制从内置JavaScript对象派生的对象会导致额外的、不需要的财产。这不是问题,因为我正在复制我自己的一个文字构造对象。
如何正确克隆JavaScript对象?
当前回答
我已经在标量对象的情况下尝试过这一点,它对我很有用:
function binder(i) {
return function () {
return i;
};
}
a=1;
b=binder(a)(); // copy value of a into b
alert(++a); // 2
alert(b); // still 1
当做
其他回答
这是对A.Levy代码的修改,以处理函数和多个/循环引用的克隆。这意味着,如果克隆的树中的两个财产是同一对象的引用,则克隆的对象树将使这些财产指向被引用对象的同一克隆。这也解决了循环依赖性的问题,如果不加以处理,就会导致无限循环。算法的复杂度为O(n)
function clone(obj){
var clonedObjectsArray = [];
var originalObjectsArray = []; //used to remove the unique ids when finished
var next_objid = 0;
function objectId(obj) {
if (obj == null) return null;
if (obj.__obj_id == undefined){
obj.__obj_id = next_objid++;
originalObjectsArray[obj.__obj_id] = obj;
}
return obj.__obj_id;
}
function cloneRecursive(obj) {
if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;
// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0; i < obj.length; ++i) {
copy[i] = cloneRecursive(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
if (clonedObjectsArray[objectId(obj)] != undefined)
return clonedObjectsArray[objectId(obj)];
var copy;
if (obj instanceof Function)//Handle Function
copy = function(){return obj.apply(this, arguments);};
else
copy = {};
clonedObjectsArray[objectId(obj)] = copy;
for (var attr in obj)
if (attr != "__obj_id" && obj.hasOwnProperty(attr))
copy[attr] = cloneRecursive(obj[attr]);
return copy;
}
throw new Error("Unable to copy obj! Its type isn't supported.");
}
var cloneObj = cloneRecursive(obj);
//remove the unique ids
for (var i = 0; i < originalObjectsArray.length; i++)
{
delete originalObjectsArray[i].__obj_id;
};
return cloneObj;
}
一些快速测试
var auxobj = {
prop1 : "prop1 aux val",
prop2 : ["prop2 item1", "prop2 item2"]
};
var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;
obj.f1 = function (){
this.prop1 = "prop1 val changed by f1";
};
objclone = clone(obj);
//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));
objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));
objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));
在ES-6中,您可以简单地使用Object.assign(…)。前任:
let obj = {person: 'Thor Odinson'};
let clone = Object.assign({}, obj);
这里有一个很好的参考:https://googlechrome.github.io/samples/object-assign-es6/
我不知道这在哪些情况下不起作用,但它给了我一个数组的副本。我觉得它很可爱:)希望它有帮助
copiedArr = origArr.filter(function(x){return true})
Jan Turo的上述答案非常接近,由于兼容性问题,可能是在浏览器中使用的最佳选择,但这可能会导致一些奇怪的枚举问题。例如,执行:
for ( var i in someArray ) { ... }
在遍历数组元素后,将clone()方法赋给i。下面是一个避免枚举并适用于node.js的改编:
Object.defineProperty( Object.prototype, "clone", {
value: function() {
if ( this.cloneNode )
{
return this.cloneNode( true );
}
var copy = this instanceof Array ? [] : {};
for( var attr in this )
{
if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone )
{
copy[ attr ] = this[ attr ];
}
else if ( this[ attr ] == this )
{
copy[ attr ] = copy;
}
else
{
copy[ attr ] = this[ attr ].clone();
}
}
return copy;
}
});
Object.defineProperty( Date.prototype, "clone", {
value: function() {
var copy = new Date();
copy.setTime( this.getTime() );
return copy;
}
});
Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );
这避免了使clone()方法可枚举,因为defineProperty()默认为false。
如果您正在使用TypeScript,需要支持较旧的web浏览器(因此无法使用Object.assign),并且没有使用内置有克隆方法的库,那么您可以在几行代码中使自己成为组合助手。它结合了对象,如果只有一个,就克隆它。
/** Creates a new object that combines the properties of the specified objects. */
function combine(...objs: {}[]) {
const combined = {};
objs.forEach(o => Object.keys(o).forEach(p => combined[p] = o[p]));
return combined;
}