我看到两种复制对象的方法
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
第一个比第二个短,那么第二个例子的效率是多少?
答案 0 :(得分:12)
在第一个版本中,您不会复制/克隆对象,只需对其进行额外的引用:
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;
}
答案 1 :(得分:7)
第一个不创建副本,只是复制引用,因此a
和b
指向操作后的同一个对象。
然而,在第二种情况下,每个属性都是单独复制的,因此在a
中创建对象的“真实”副本(只要属性中只有原始类型,否则你会得到相同的更深层次的问题)。
因此,在第一种情况下,如果您更改b.c
,则a.c
也会发生变化,而在第二种情况下则不会发生变化。
答案 2 :(得分:4)
正如其他人在此处所述:第一项作业,为现有对象指定新引用,第二项指定执行浅层复制。
通过浅 I mean:只复制基础对象,没有递归:
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
)时你认为仍然存在的东西
答案 3 :(得分:3)
第一个复制引用, 不复制 对象,第二个创建一个新引用,然后复制成员(反过来,如果它们是引用只会复制参考文献。
你可能想看看其他的SO - Does Javascript equal sign reference objects or clones them?
这不是效率问题,而是最终的正确性。如果您需要在不同代码块之间共享对象的引用(例如,以便多个代码段可以共享同一个对象) - 那么您只需依赖于javascript通过引用传递的事实。
但是,如果您需要在方法之间复制对象 - 那么您可以在第二个代码块中使用您的简单示例(如果您的对象中没有其他'对象'),否则您可能必须实施深度克隆(请参阅How to Deep clone in javascript,并注意那里的答案 - 这不是一项微不足道的事情。)