我看到了两种复制对象的方法
1.
var a={c:1}
var b=a;
alert(b.c);//alert 1
2.
var a={c:2};
var b={};
for (i in a)
{b[i]=a[i];}
alert(b.c);//alert 1
第一个比第二个短,那么第二个例子的效率是多少?
我看到了两种复制对象的方法
1.
var a={c:1}
var b=a;
alert(b.c);//alert 1
2.
var a={c:2};
var b={};
for (i in a)
{b[i]=a[i];}
alert(b.c);//alert 1
第一个比第二个短,那么第二个例子的效率是多少?
在第一个版本中,您不会复制/克隆对象,只需对其进行额外引用:
var a = { a: 1 };
var b = a;
b.a = 2;
console.log(a.a); // 2;
要克隆一个对象,有许多库可以为您做到这一点:
var b = $.extend({}, a); // Make a shallow clone (jQuery)
var b _.extend({}, a); // Make a shallow clone (underscore.js)
var b = $.extend(true, {}, a); // Make a deep clone (jQuery);
或者您可以在本地进行:
简单克隆:
var b = {};
var prop;
for (prop in a) {
b[prop] = a[prop];
}
深度克隆功能的草稿:
function deepClone(obj) {
var r;
var i = 0,
var len = obj.length;
// string, number, boolean
if (typeof obj !== "object") {
r = obj;
}
// Simple check for array
else if ( len ) {
r = [];
for ( ; i < len; i++ ) {
r.push( deepClone(obj[i]) );
}
}
// Simple check for date
else if ( obj.getTime ) {
r = new Date( +obj );
}
// Simple check for DOM node
else if ( obj.nodeName ) {
r = obj;
}
// Object
else {
r = {};
for (i in obj) {
r[i] = deepClone(obj[i]);
}
}
return r;
}
第一个不创建副本,而只是复制引用,因此操作a
后b
指向同一个对象。
然而,在第二种情况下,每个属性都被单独复制,从而在其中创建对象的“真实”副本a
(只要属性中只有原始类型,否则在更深层次上会遇到同样的问题)。
因此,在第一种情况下,如果您更改,b.c
那么a.c
也会更改,而在第二种情况下则不会。
正如其他人在这里所说:第一个分配,为现有对象分配一个新引用,第二个执行浅拷贝。浅
我的意思是:只会复制基础对象,没有递归:
var a = {some:'propery',
another:{might:'be',
an: 'object, too'}
};
var b = {};
for(var p in a)
{
b[p] = a[p];
}
b.some = 'b\'s own property';
console.log(a.some);//property -> unaltered
console.log(b.some);//b's own property --> separate entities
b.another.might = 'foo';
console.log(a.another.might);//foo ==> b.another references a.another
为了解决这个问题,你会认为一个简单的递归函数就足够了:
var cloneObj = function(o)
{
var p,r = {};
for (p in o)
{//omitting checks for functions, date objects and the like
r[p] = (o[p] instanceof Object ? cloneObj(o[p]) : o[p]);
}
};
但要厌倦循环引用!
//assume a is the same object as above
a._myself = a;//<- a references itself
这将产生无休止的递归,也就是死锁场景,除非您针对这种情况添加检查:
var cloneObj = function(o)
{
var p,r = {};
for (p in o)
{//Needs a lot more work, just a basic example of a recursive copy function
switch(true)
{
case o[p] instanceof Function:
r[p] = o[p];
break;
case o[p] instanceof Date:
r[p] = new Date(o[p]);
break;
case o === o[p]:
//simple circular references only
//a.some.child.object.references = a; will still cause trouble
r[p] = r;
break;
case o[p] instanceof Array:
r[p] = o[p].slice(0);//copy arrays
break;
default:
r[p] = o[p] instanceof Object ? cloneObj(o[p]) : o[p];
}
}
return r;
};
现在,这非常冗长,并且在大多数情况下完全过分,如果您想要的是两个具有相同数据但可以独立更改的对象(即不要在内存中引用相同的对象),那么您只需要 1 行代码:
var a = {some:'propery',
another:{might:'be',
an: 'object, too'}
};
var b = JSON.parse(JSON.stringify(a));
底线:分配引用肯定更有效:它不需要第二次调用对象构造函数,也不需要任何常量的额外副本。
缺点是:您最终得到一个对象,并且可能会无意中更改/删除您认为在使用其他引用时仍然存在的东西(delete b.some;/*some time later*/a.some.replace(/p/g,'q');//<--error
)
第一个复制引用并且不复制对象,第二个创建一个新引用然后复制成员(反过来,如果它们是引用将只复制引用)。
您可能想查看其他 SO - Javascript 是否等于号引用对象或克隆它们?
这不是效率问题,最终是关于正确性的问题。如果您需要在不同的代码块之间共享对对象的引用(例如,以便多段代码可以共享同一个对象),那么您只需依赖 javascript 通过引用传递的事实。
但是,如果您需要在方法之间复制一个对象 - 那么您可以在第二个代码块中使用您的简单示例(如果您的对象中没有其他“对象”),否则您可能必须实现深度克隆(请参阅How to Deep clone in javascript,并注意那里的答案 - 这不是一件小事)。