Bir Haritayı Yinelenen Bir Haritaya Nasıl Kopyalarım? [çiftleme]


95

JavaScript'te bir haritayı nasıl klonlarım / kopyalarım?

Bir diziyi nasıl klonlayacağımı biliyorum ama bir haritayı nasıl klonlarım / kopyalarım?

var myArray = new Array(1, 2, 3);
var copy    = myArray.slice();
// now I can change myArray[0] = 5; & it wont affect copy array

// Can I just do the same for map?
var myMap = new ?? // in javascript is it called a map?
var myMap = {"1": 1, "2", 2};
var copy  = myMap.slice(); 

3
ES6 size izin veriyorlet copy = {...myMap};
Reactgular

Yanıtlar:


15

Basit bir yol (sığ bir kopya yapmanın), kaynak haritanın her bir özelliğini hedef haritaya kopyalamaktır:

var newMap = {};
for (var i in myMap)
   newMap[i] = myMap[i];

NOT: newMap [i], myMap [i] ile aynı nesneye çok iyi bir referans olabilir.


6
bu yalnızca yüzeysel bir kopya ... peki ya myMap [i] bir haritanın kendisi ise?
Stefano

1
Stefano, eğer istersen bunu yapabilirsin (typeof ile bir nesne olup olmadığını kontrol et, sonra onun özelliklerinin bir kopyasını gerçekleştir ... muhtemelen aynı işlevi tekrarlayarak), ama şimdi de şunu unutma ki, Sizi sonsuz bir döngüye sokacak bir ata unsuru olma olasılıkları. Gerçekten derin bir kopya istiyorsanız, bunu yapmak için kitaplıklara bakmak isteyebilirsiniz.
soymak

4
Biliyorum, ama bence bunu cevabına ilk etapta yazman gerekirdi ;-)
Stefano

6
Bu bir Harita değil, bir Nesnedir. Küçük ve ince fark. cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
helt

1
Ayarlayıcılara ve alıcılara erişemeyeceğiniz her mülkü sadece bir nesne olarak kopyalamayacaktır
Amante Ninja

351

Haritalar'ın JavaScript'te sunulmasıyla, kurucunun yinelenebilir bir şeyi kabul ettiğini düşünmek oldukça basit:

var newMap = new Map(existingMap)

Belgeler burada: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


4
Yukarıdakilere küçük bir uyarı: Bunun gibi bir haritayı klonlamak Map.prototype.entriesve çağıracaktır Map.prototype.set. Bunun anlamı: Map'i genişleten ve bu iki yöntemden birinin üzerine yazan bir sınıf yazarsanız new ExtendedMap( extendedMapObj ), genişletilmiş yöntemler süper tarafından kullanılamayan özelliklere dayanıyorsa, basitçe yazmak işe yaramayacaktır.

derin klon mu yoksa sadece sığ klon mu? Diyelim ki değer olarak iç içe
nesnem var

ama derin veya sığ bir kopya mı yapıyor?
Yonatan Nir

5
Bu, derin değil, sığ bir kopya oluşturacak: jsfiddle.net/jormwe69
Jaap

1
@PeterCoester Can biz asymptotiki demek var newMap = new Map(existingMap)olduğunu O(n)nerede nharitanın anahtar / değer çiftleri sayısıdır? Sanırım klonlama işlemi, O(1)dediğiniz gibi Map.prototype.entries , kaputun altında çağrılırsa sabit değildir ...
tonix

10

Bahsettiğiniz şey sadece bir nesne olduğu için bir haritayı klonlamak çok basit. Bir Orada Mapsen, sadece kullanım bakmak gerekir, ancak bir nesneyi kopyalamak için bu ES6 içindeObject.assign()

let map = {"a": 1, "b": 2}
let copy = Object.assign({}, map);

cloneDeep()Lodash'tan da kullanabilirsiniz

let copy = cloneDeep(map);

Object.assignDerin Klon için Uyarı: "Kaynak değeri bir nesneye başvuruysa, yalnızca referans değerini kopyalar."
Tom Hale

6

JQuery, bir nesneyi genişletmek için (iki nesneyi birleştirmek) için bir yönteme sahiptir, ancak bu yöntem, boş bir nesne sağlayarak bir nesneyi klonlamak için de kullanılabilir.

// Shallow copy
var newObject = jQuery.extend({}, oldObject);

// Deep copy
var newObject = jQuery.extend(true, {}, oldObject);

JQuery belgelerinde daha fazla bilgi bulunabilir .


3

Yerleşik hiçbir şey yok.

İyi test edilmiş bir özyinelemeli özellik kopyalayıcı kullanın veya performans bir sorun değilse, JSON'a serileştirin ve yeni bir nesneye yeniden ayrıştırın.


2

Yerleşik klon / kopya yoktur. Sığ veya derin kopya olarak kendi yönteminizi yazabilirsiniz:

function shallowCopy(obj) {
    var result = {};
    for (var i in obj) {
        result[i] = obj[i];
    }
    return result;
}

function deepCopy(obj) {
    var result = {};
    for (var i in obj) {
        // recursion here, though you'll need some non-trivial logic
        // to avoid getting into an endless loop.
    }
    return result;
}

Javascript'teki tüm nesneler dinamiktir ve yeni özellikler atanabilir. Sizin bahsettiğiniz şekliyle bir "harita" aslında sadece boş bir nesnedir. Bir Dizi aynı zamanda gibi yöntemler sliceve benzeri özelliklere sahip bir nesnedir length.


Yazdığınız 2 işlev arasındaki farkın ne olduğunu anlamadınız!
Hasan A Yousef

@HasanAYousef Fark uygulanmaz; Derin bir kopyada, yinelemelisiniz (her çocuk için deepCopy çağırın), ancak çocuklar üst öğeye bir referans içerebileceğinden (örn. Window.window2 = window), bu referansları sonsuz bir döngüye girmeden derinlemesine kopyalayamazsınız.
Nicole

2

Bir Haritanın derin bir kopyasını almanız gerekiyorsa, aşağıdakileri kullanabilirsiniz:

new Map(JSON.parse(JSON.stringify(Array.from(source))));

Nerede sourceOrijinal Harita nesnesi .

Bunun, Harita değerlerinin serileştirilemediği tüm kullanım durumları için uygun olmayabileceğini unutmayın, daha fazla ayrıntı için bkz .: https://stackoverflow.com/a/122704/10583071


Jsperf üzerinde bir test yaptım ve yinelemeli yaklaşımın 10 kat daha hızlı olduğunu buldum: jsperf.com/deep-copy-map
Zack Burt

2
@ZackBurt Ne yazık ki, daha hızlı önerilen alternatifiniz gerçekten bir deep copyhedef oluşturmuyor , Mapsadece bir shallow copy. Belki de bu yüzden bu kadar hızlı?
Alfonso M. García Astorga

@ AlfonsoM.GarcíaAstorga Açıklığa kavuşturduğunuz için teşekkür ederiz (buna göre oy verildi). Öyle ki Sen doğru değil derin kopyası. Ancak, <10 kb veri ile daha hızlı bir kopyadır. Önerilen ek okuma: v8.dev/blog/cost-of-javascript-2019#json
Zack Burt

1

Haritanın özel işlem gerektirmesi gerektiğini fark ettim, bu nedenle bu başlıktaki tüm önerilerle birlikte kod şöyle olacaktır:

function deepClone( obj ) {
    if( !obj || true == obj ) //this also handles boolean as true and false
        return obj;
    var objType = typeof( obj );
    if( "number" == objType || "string" == objType ) // add your immutables here
        return obj;
    var result = Array.isArray( obj ) ? [] : !obj.constructor ? {} : new obj.constructor();
    if( obj instanceof Map )
        for( var key of obj.keys() )
            result.set( key, deepClone( obj.get( key ) ) );
    for( var key in obj )
        if( obj.hasOwnProperty( key ) )
            result[key] = deepClone( obj[ key ] );
    return result;
}

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.