8

オブジェクトを複製する方法が 2 つあります

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

最初の例は 2 番目の例よりも短いので、2 番目の例の効率はどうなりますか?

4

4 に答える 4

13

最初のバージョンでは、オブジェクトを複製/複製せず、オブジェクトへの追加の参照を作成するだけです:

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;
}
于 2012-11-08T10:39:32.840 に答える
8

最初はコピーを作成せず、参照をコピーするだけなのでab操作後に同じオブジェクトを指します。

ただし、2 番目のケースでは、各属性が個別にコピーされるため、オブジェクトの "実際の" コピーが作成されますa(プロパティにプリミティブ型しかない場合は、より深いレベルで同じ問題が発生します)。

したがって、最初のケースでは変更すると変更も行われますb.ca.c、2 番目のケースでは変更されません。

于 2012-11-08T10:39:00.750 に答える
4

他の人がここで述べているように: 最初の代入は既存のオブジェクトに新しい参照を割り当て、2 番目は浅いコピーを実行します。つまり、基本オブジェクトのみがコピーされ、再帰はありません

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;
};

さて、これは非常に冗長で、ほとんどの場合完全にやり過ぎです。必要なのは同じデータを持つ 2 つのオブジェクトだけで、独立して変更できる (つまり、メモリ内の同じオブジェクトを参照しない) 場合、必要なのは 1 行だけです。コードの:

var a = {some:'propery',
         another:{might:'be',
                  an: 'object, too'}
        };
var b = JSON.parse(JSON.stringify(a));

結論: 参照を割り当てる方が確かに効率的です。オブジェクト コンストラクターを 2 回呼び出す必要はなく、定数のコピーを追加する必要もありません。
欠点は、単一のオブジェクトになってしまい、他の参照を使用しているときにまだそこにあると想定しているものを誤って変更/削除する可能性があることです ( delete b.some;/*some time later*/a.some.replace(/p/g,'q');//<--error)

于 2012-11-08T11:10:08.773 に答える
3

1 つ目は参照をコピーし、オブジェクトを複製しません。2 つ目は新しい参照を作成してからメンバーをコピーします (つまり、参照の場合は、参照のみをコピーします)。

この他のSOを見たいと思うかもしれません - Javascriptの等号はオブジェクトを参照するか、それらを複製しますか?

効率の問題ではなく、最終的には正確性の問題です。異なるコード ブロック間でオブジェクトへの参照を共有する必要がある場合 (たとえば、複数のコード片が同じオブジェクトを共有できるようにするため)、javascript が参照渡しであるという事実に依存するだけです。

ただし、メソッド間でオブジェクトをコピーする必要がある場合は、2 番目のコード ブロックで簡単な例を使用できる場合があります (オブジェクトに他の「オブジェクト」が含まれていない場合)。それ以外の場合は、実装する必要があります。ディープ クローン (javascript でディープ クローンを作成する方法を参照し、そこにある回答に注意してください - それは些細な仕事ではありません)。

于 2012-11-08T10:39:20.660 に答える