171

How do I clone/copy a Map in JavaScript?

I know how to clone an array, but how do I clone/copy a Map?

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
  • 7
    ES6 lets you let copy = {...myMap}; Commented Feb 10, 2019 at 14:19
  • 2
    Sorry to be pedantic, but this was not permitted in ES6; rather, it was introduced in ES9 a.k.a ES2018. You could spread arrays in ES6 a.k.a ES2015 but not object literals. Commented Jul 4, 2021 at 7:57

8 Answers 8

559

With the introduction of Maps in JavaScript it's quite simple considering the constructor accepts an iterable:

var newMap = new Map(existingMap)

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

Sign up to request clarification or add additional context in comments.

8 Comments

A small caveat to the above: Cloning a map like this, will invoke Map.prototype.entries and Map.prototype.set. That means: If you write a class that extends Map and overwrites either of these two methods, then simply writing new ExtendedMap( extendedMapObj ) will not work if the extended methods rely on properties that are not available to the super.
does it deep clone or just shallow clone? Let's say I have nested object as values
but does it do a deep or a shallow copy??
This will do a shallow copy, not deep: jsfiddle.net/jormwe69
@PeterCoester Can we say that the asymptotic of var newMap = new Map(existingMap) is O(n) where n is the number of the key/value pairs of the map? I guess that the cloning operation is not constant O(1) if, as you say, Map.prototype.entries is called under the hood...
|
11

A simple way (to do a shallow copy) is to copy each property of the source map to the target map:

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

NOTE: newMap[i] could very well be a reference to the same object as myMap[i]

6 Comments

this is a shallow copy only... what if myMap[i] is a map itself?
Stefano, you can do that if you want (check if if is an object with typeof, then perform a copy of it's properties...possibly by recursing the same function), but keep in mind that now you have to be concerned about the possibility of their being an ancestor element in their which would put you in an infinite loop. If you really want a deep copy, you may want to look into libraries for doing that.
I know, but I think you should have written this in your answer in the first place ;-)
This is not a Map but an Object. Small and suble difference. cf. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
It will not copy each property you wont have the access to setters and getters as its just an object
|
10

If you need to make a deep copy of a Map you can use the following:

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

Where source is the original Map object.

Note this may not be suitable for all use cases where the Map values are not serializable, for more details see: https://stackoverflow.com/a/122704/10583071

4 Comments

I ran a test on jsperf and found that an iterative approach is 10x faster: jsperf.com/deep-copy-map
@ZackBurt Sadly, your faster proposed alternative does not create really a deep copy of the target Map it's just a shallow copy. Maybe is this why it's so fast?
@AlfonsoM.GarcíaAstorga Thank you for clarifying (upvoted accordingly). You are correct in that it is not a deep copy. But it is a faster copy with <10kb of data. Recommended supplemental reading: v8.dev/blog/cost-of-javascript-2019#json
this solution is popular throughout the web, but it transforms data and doesn't handle nesting.
9

Very simple to just use Object.assign()

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

// Or

const copy = Object.assign({}, {'a': 1, 'b': 2});

2 Comments

Object.assign Warning for Deep Clone: "If the source value is a reference to an object, it only copies the reference value."
This answer is about a generic Object being used in place of a Map, but the OP asked about an actual Map instance.
4

JQuery has a method to extend an object (merging two objects), but this method can also be used to clone an object by providing an empty object.

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

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

More information can be found in the jQuery documentation.

Comments

3

There is nothing built in.

Either use a well tested recursive property copier or if performance isn't an issue, serialise to JSON and parse again to a new object.

Comments

2

There is no built-in (edit: DEEP) clone/copy. You can write your own method to either shallow or deep copy:

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

[EDIT] Shallow copy is built-in, using Object.assign:

let result = Object.assign({}, obj);

All objects in Javascript are dynamic, and can be assigned new properties. A "map" as you refer to it is actually just an empty object. An Array is also an object, with methods such as slice and properties like length.

6 Comments

Did not understand what is the different between the 2 functions you wrote!
@HasanAYousef The difference is not implemented; In a deep copy, you must recurse (call deepCopy for each child), but because children may contain a reference to the parent (e.g. window.window2 = window), you cannot deep copy those references without getting into an endless loop.
javascript doesn't even have a copy by value? smh. and people love this language.
@ahnbizcad It's basically exactly the same as Java. tl;dr everything is "copy by value" and all values are references except primitives. What it doesn't have natively is a deep copy, which neither does Java. Neither does C, I imagine? Most OOP languages don't automatically deep copy complex objects, that would be a nightmare. I recommend learning JS to learn its benefits 😊
deep/shallow copy is a terrible, obscuring term. it's copy by reference. the opposite is copy by value, which primitives are. the language doesn't have copy by value. or even an option to. JSON.stringify doesn't work. it fails at doing multidimensional arrays, and transforms all kinds of data into other data.
|
1

I noticed that Map should require special treatment, thus with all suggestions in this thread, code will be:

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.