javascript中的重复对象

时间:2012-11-08 10:35:46

标签: javascript object

我看到两种复制对象的方法

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

第一个比第二个短,那么第二个例子的效率是多少?

4 个答案:

答案 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)

第一个不创建副本,只是复制引用,因此ab指向操作后的同一个对象。

然而,在第二种情况下,每个属性都是单独复制的,因此在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,并注意那里的答案 - 这不是一项微不足道的事情。)