Клонуйте / скопіюйте екземпляр Карти


88

Як клонувати / копіювати карту в JavaScript?

Я знаю, як клонувати масив, але як клонувати / копіювати карту?

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(); 

2
ES6 дозволяєlet copy = {...myMap};
реагуючи на

Відповіді:


17

Простий спосіб (зробити неглибоку копію) - скопіювати кожну властивість вихідної карти на цільову карту:

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

ПРИМІТКА: newMap [i] цілком може бути посиланням на той самий об'єкт, що і myMap [i]


6
це лише неглибока копія ... що, якщо myMap [i] - це сама карта?
Стефано

1
Стефано, ви можете зробити це, якщо хочете (перевірте, якщо це об’єкт із typeof, а потім виконайте копію його властивостей ... можливо, повторивши ту саму функцію), але майте на увазі, що тепер ви повинні турбуватися про можливість їхнього елемента-прабатька, який би ввів вас у нескінченний цикл. Якщо ви дійсно хочете глибоку копію, можливо, ви захочете заглянути в бібліотеки для цього.
грабувати

4
Я знаю, але я думаю, що ти мав би це спочатку написати у своїй відповіді ;-)
Стефано,

5
Це не Карта, а Об’єкт. Мала і сублімарна різниця. пор. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
helt

1
Він не буде копіювати кожну властивість, до якої ви не матимете доступу до сетерів та геттерів, оскільки це просто об’єкт
Amante Ninja

329

З введенням Maps у JavaScript це досить просто, враховуючи, що конструктор приймає ітерацію:

var newMap = new Map(existingMap)

Документація тут: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map


4
Невелике застереження до вищезазначеного: клонування такої карти викликає Map.prototype.entriesі Map.prototype.set. Це означає: Якщо ви пишете клас, який розширює Map і перезаписує будь-який з цих двох методів, тоді просто написання new ExtendedMap( extendedMapObj )не буде працювати, якщо розширені методи покладаються на властивості, недоступні супер.

це глибокий клон чи просто неглибокий? Скажімо, я
Madeo,

але це робить глибоку або неглибоку копію ??
Йонатан Нір,

5
Це зробить неглибоку копію, а не глибоку: jsfiddle.net/jormwe69
Яап,

1
@PeterCoester Чи можна сказати, що асимптотикою var newMap = new Map(existingMap)є те, O(n)де nє число пар ключ / значення на карті? Я припускаю, що операція клонування не є постійною, O(1)якщо, як ти кажеш, Map.prototype.entries викликається під капотом ...
tonix

11

Клонувати карту дуже просто, оскільки те, про що ви говорите, це просто об’єкт. Є MapES6, який слід шукати, але щоб скопіювати об’єкт, просто скористайтеся нимObject.assign()

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

Ви також можете використовувати cloneDeep()від Lodash

let copy = cloneDeep(map);

6

JQuery має метод розширення об'єкта (об'єднання двох об'єктів), але цей метод також може бути використаний для клонування об'єкта, надавши порожній об'єкт.

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

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

Більше інформації можна знайти в документації jQuery .


3

Тут нічого не вбудовано.

Або використовуйте добре перевірений рекурсивний копір властивостей, або якщо продуктивність не є проблемою, серіалізуйте JSON і знову проаналізуйте новий об’єкт.


2

Немає вбудованого клону / копії. Ви можете написати свій власний метод як на поверхневій, так і на глибокій копії:

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 є динамічними, і їм можуть бути призначені нові властивості. "Карта", коли ви до неї звертаєтесь, насправді є просто порожнім об'єктом. Масив - це також об'єкт із такими методами як sliceі властивостями length.


Не зрозумів, чим відрізняються 2 написані вами функції!
Hasan A Yousef

@HasanAYousef Різниця не реалізована; У глибокій копії ви повинні повторити (викликати deepCopy для кожної дочірньої організації), але оскільки діти можуть містити посилання на батьківського елемента (наприклад, window.window2 = window), ви не можете глибоко копіювати ці посилання, не потрапляючи в нескінченний цикл.
Ніколь

2

Якщо вам потрібно зробити глибоку копію карти, ви можете використовувати наступне:

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

Де sourceзнаходиться оригінальний об’єкт Карти.

Зверніть увагу, що це може не підходити для всіх випадків використання, коли значення карти не можна серіалізувати, докладніше див .: https://stackoverflow.com/a/122704/10583071


Я провів тест на jsperf і виявив, що ітераційний підхід в 10 разів швидший: jsperf.com/deep-copy-map
Зак Берт

2
@ZackBurt На жаль, запропонована вами швидша альтернатива насправді не створює deep copyцілі, якою Mapвона є shallow copy. Може, тому це так швидко?
Альфонсо М. Гарсія Асторга

@ AlfonsoM.GarcíaAstorga Дякуємо за роз'яснення (відповідно проголосували). Ви праві, вважаючи, що це не глибока копія. Але це швидша копія з <10 кб даних. Рекомендоване додаткове читання: v8.dev/blog/cost-of-javascript-2019#json
Зак Берт,

1

Я помітив, що Map повинен вимагати особливого ставлення, тому з усіма пропозиціями в цій темі код буде таким:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.