1console.log("hello-world);
javascript
console.log("hello-world);
hidden codeblock for CSS
css
.container {
  width: 80%;
}
hidden codeblock for CSS
html
<pre><code class="language-css">
.container {
  width: 80%;
}
</code></pre>
hidden codeblock for CSS
1console.log("hello-world);
javascript
console.log("hello-world);
hidden codeblock for CSS
css
.container {
  width: 80%;
}
hidden codeblock for CSS
html
<pre><code class="language-css">
.container {
  width: 80%;
}
</code></pre>
hidden codeblock for CSS

How to Convert Map To Object in Javascript And Reverse

ReadTime: 12 minutes

Today, we will dive deep into converting Maps to Objects in JavaScript and back. We’ll learn core differences between Map and Object, master various conversion techniques for simple and complex Maps (like deeply nested maps), and even how to Objects back into Maps. You will learn some best practices and performance tips for large data sets, and some common mistakes. Ready to dive in?


Refresher: Maps and Objects in JavaScript:

JavaScript offers a variety of ways to store and manage data. Two such are Maps and Objects.

  • JavaScript Maps: Introduced in ES6, Maps are collections that store key-value pairs. They can have keys of any data type and maintain the order of insertion, which is a significant advantage over Objects.
  • JavaScript Objects: Traditional key-value pairs where keys are typically strings. Objects don’t preserve the order of insertion and aren’t as flexible with key types as Maps.
  • Understanding these structures, and how we can convert amongst them, is crucial as they offer different benefits suitable for various scenarios.
JavaScript (Creating Map and Object)
javascript
// Creating Map:
let map = new Map();
map.set('key1', 'value1');
map.set('key2', 'value2');
console.log(map); // Map(2) {"key1" => "value1", "key2" => "value2"}

// Creating Map using Constructor initialisation:
//  - using 2 Dimensional array of [[Key, Value], ... ]
let map2 = new Map([['key1', 'value1'], ['key2', 'value2']]);
console.log(map2); // Map(2) {"key1" => "value1", "key2" => "value2"}

// Creating Object:
let obj = { key1: 'value1', key2: 'value2' };
console.log(obj); // {key1: "value1", key2: "value2"}

Real world Application: Map, Object and their Conversion

Map-to-Object conversion is often used in API development, particularly when preparing data for JSON serialization to send as an API response. You cant convert Map (or even Set) directly to JSON. First we need to convert into Object (or a Multidimensional array). If you use JSON.stringify() on Map, then you get empty object.

JavaScript Map & Object (Real World Application)
javascript
function prepareDataForAPI(mapData) {
  return JSON.stringify(Object.fromEntries(mapData));
}

// Example Map representing API data
let apiData = new Map([['userId', 1], ['username', 'johndoe']]);
let jsonData = prepareDataForAPI(apiData);

console.log(jsonData);
// Outputs '{"userId":1,"username":"johndoe"}'

Ways to Convert Map To Object in Javascript

Using Object.fromEntries():

This method is a straightforward way to transform a Map into an Object. It accepts an iterable of key-value pairs and constructs an object out of them. This method shines due to its simplicity and readability.

javascript
let map = new Map([['key1', 'value1'], ['key2', 'value2']]);
let obj = Object.fromEntries(map);
console.log(obj); // {key1: "value1", key2: "value2"}
Object.fromEntries() to convert a Map to Object

Using Loops:

Using Map.forEach():

The Map.forEach() method provides control while adding each element into Object.

javascript
let map = new Map([['key1', 'value1'], ['key2', 'value2']]);
let obj = {};
map.forEach((value, key) => { obj[key] = value; });
console.log(obj); // {key1: "value1", key2: "value2"}
Map.foreach() to convert a Map to Object

Utilizing the for…of Loop:

The for...of loop is an alternative iteration method that also provides direct access to the Map’s entries while adding to Object.

javascript
let map = new Map([['key1', 'value1'], ['key2', 'value2']]);
let obj = {};
for (let [key, value] of map) { obj[key] = value; }
console.log(obj); // {key1: "value1", key2: "value2"}
for...of loop to convert a Map to Object

Advanced Techniques for Map-to-Object Conversion

When converting Maps to Objects in JavaScript, especially those with nested structures or non-string keys, the process requires special handling to ensure data integrity.

Handling Nested Maps Structures

A Map may contain other Maps or Objects as its values, and these nested structures must be correctly converted into a corresponding nested Object structure.

javascript
function deepMapToObject(map) {
  const obj = {};
  for (let [key, value] of map) {
      if (value instanceof Map) {
          obj[key] = deepMapToObject(value);
      } else {
          obj[key] = value;
      }
  }
  return obj;
}

const nestedMap = new Map([
  ['level1', new Map([
      ['level2', 'value']
  ])]
]);

const nestedObj = deepMapToObject(nestedMap);
console.log(nestedObj);
// Output: { level1: { level2: 'value' } }
Nested Map to Object conversion
  • The deepMapToObject function recursively converts each entry of the Map.
  • If a value is an instance of Map, the function calls itself recursively, ensuring nested Maps are also converted into Objects.
  • This approach maintains the nested structure within the resulting Object.

Handling Maps with Non-String Keys

JavaScript Objects can only have strings or symbols as keys. When converting a Map (which can have keys of any type) to an Object, non-string keys need special treatment.

javascript
function mapToObjectWithNonStringKeys(map) {
  const obj = {};
  for (let [key, value] of map) {
      const strKey = typeof key === 'object' ? JSON.stringify(key) : key.toString();
      obj[strKey] = value;
  }
  return obj;
}

const mapWithNonStringKeys = new Map([
  [{ id: 1 }, 'value1'],
  [3, 'value3']
]);

const objFromMap = mapToObjectWithNonStringKeys(mapWithNonStringKeys);
console.log(objFromMap);
// Output: { '{"id":1}': 'value1', '3': 'value3' }
Non-String Keys in Map to Object conversion
  • In mapToObjectWithNonStringKeys, each key is checked for its type.
  • If the key is an object, it’s stringified using JSON.stringify; otherwise, toString() is used to ensure all keys in the resulting Object are strings.
  • This conversion allows the Map’s structure to be represented accurately in an Object, albeit with stringified representations of non-string keys.

Converting Javascript Objects to Maps

Reversing the conversion is equally important. Converting Objects back to Maps is straightforward but requires understanding the nuances of Object entries.

javascript
function objectToMap(obj) {
  return new Map(Object.entries(obj));
}

let obj = { key1: 'value1', key2: 'value2' };
let mapFromObj = objectToMap(obj);

console.log(mapFromObj); // Map(2) {"key1" => "value1", "key2" => "value2"}
Converting Object to Map

Tips on Javascript Map to Object Conversion

Apart from Nested Data Structures or Non String Keys as described above, following tips can further enahnce your skills on Javascript Map to Object Conversion.

Incorrect Usage of JSON.stringify()

It's a common error to use JSON.stringify() directly on a Map, expecting it to be converted to an Object. This results in an empty object as JSON.stringify() cannot serialize Map keys and values correctly.

javascript
let map = new Map([['key1', 'value1'], ['key2', 'value2']]);
  
// Incorrect approach:
let incorrectSerialization = JSON.stringify(map);
console.log(incorrectSerialization);
// Outputs ❌ "{}"

// Correct approach(using Object conversion)
let correctSerialization = JSON.stringify(Object.fromEntries(map));
console.log(correctSerialization);
// Outputs ✅ '{"key1":"value1","key2":"value2"}'
Incorrectly using JSON.stringify() on map

Performance Tips

  • Can you get away without conversion? 😁 No? Then minimize the number of conversions. If still issues, then explore following 3 techniques.

Chunking

When dealing with very large Maps in JavaScript, converting them directly to Objects can be resource-intensive. To alleviate this, a technique called “chunking” can be used. This involves breaking the conversion process into smaller, more manageable parts or ‘chunks’. This approach is particularly useful when processing large datasets that might cause performance issues, like UI freezing or memory overload.

  • In this example, we’ll demonstrate how to chunk a Map and convert each chunk to an Object. We’ll use a smaller dataset for simplicity, but this method scales well with larger datasets.
javascript
function convertMapInChunks(map, chunkSize) {
  const obj = {};
  let count = 0;
  for (let [key, value] of map) {
      obj[key] = value;
      if (++count % chunkSize === 0) {
          // Process the chunk
          console.log(`Processed chunk:`, obj);
          // Reset for next chunk
          count = 0;
      }
  }
  // Process any remaining entries in the last chunk
  if (count > 0) {
      console.log(`Processed final chunk:`, obj);
  }
  return obj;
}

// Example usage with a Map
let exampleMap = new Map([
  ['key1', 'value1'], ['key2', 'value2'],
  ['key3', 'value3'], ['key4', 'value4']
]);

let chunkedObject = convertMapInChunks(exampleMap, 2);

// The console will show two separate chunks being processed: 👇
//   Processed chunk: { key1: "value1", key2: "value2" }
//   Processed final chunk: { key3: "value3", key4: "value4" }
Using chunking to Optimize Serialization for Large Sets
  • The function convertMapInChunks takes a Map and a chunk size as inputs.
  • It iterates through the Map, adding each key-value pair to the obj.
  • Once the count reaches the chunk size, it logs the current chunk, showing how the data is processed in segments.
  • After processing each chunk, the function resets the count and the object for the next chunk.
  • Finally, it ensures any remaining entries in the Map (that didn’t make up a full chunk) are processed.

Lazy Loading

Lazy loading, in the context of JavaScript data processing, refers to loading and processing parts of a data set only as needed, rather than all at once. Specially helpful with large datasets or when enhancing performance.

  • In following example, let’s assume we have a large Map object that we need to convert to an Object, but we want to do it in a way that only the required entries are processed at a time.
javascript
function lazyLoadMapToObject(map, keysToLoad) {
  const obj = {};
  keysToLoad.forEach(key => {
      if (map.has(key)) {
        obj[key] = map.get(key);
      }
  });
  return obj;
}

// Simulating a large Map
let largeMap = new Map([...Array(1000).keys()].map(k => [k, `value${k}`]));

// Lazy loading a portion of the Map
let keysToLoad = [100, 200, 300]; // Loading only specific keys
let partialObject = lazyLoadMapToObject(largeMap, keysToLoad);

console.log(partialObject);
// Outputs: { 100: "value100", 200: "value200", 300: "value300" }
Using chunking to Optimize Serialization for Large Sets
  • The lazyLoadMapToObject function takes a Map and an array of keys that need to be loaded.
  • It iterates over the keysToLoad, checks if the Map contains each key, and if so, adds the key-value pair to the resulting Object.
  • This allows selective conversion of Map entries to an Object based on current requirements, rather than converting the entire Map.

Web Workers

Little extreme, but yes this is another way to increase the performance. Web Workers provide a way to run scripts in background threads, separate from the main execution thread of a web application. This feature is particularly useful for offloading computationally heavy tasks, like processing large data sets, without blocking the UI or other operations on the page. Here’s an example demonstrating how to use a Web Worker for converting a large Map to an Object. First, create a Web Worker script (worker.js):

Web Worker Script \`worker.js\`
javascript
// worker.js
self.onmessage = function(e) {
  const map = new Map(e.data);
  const obj = {};

  for (let [key, value] of map) {
      obj[key] = value;
  }

  self.postMessage(obj);
};
Using Web Workers for Map to Object conversion

Then, in your main script:

Main Script \`worker.js\`
javascript
// Main JavaScript file
if (window.Worker) {
  const myWorker = new Worker('worker.js');

  myWorker.onmessage = function(e) {
      console.log('Map converted to Object:', e.data);
  };

  // Example large Map
  const largeMap = new Map([...Array(1000).keys()].map(k => [k, `value${k}`]));

  myWorker.postMessage([...largeMap]);
}
Using Web Workers for Map to Object conversion
  • The worker.js script contains the logic for converting a Map to an Object. It listens for messages (onmessage) containing the Map data, processes it, and sends back the Object (postMessage).
  • In the main script, a new Worker is created and pointed to worker.js. The large Map data is sent to the Worker via postMessage.
  • The Worker processes the Map and sends back the converted Object. The main thread receives this data in the onmessage handler and logs the result.

🧪Practice Coding Problem: The Map-Object Alchemist

In the spirit of Test Driven Development ( 😁), lets test our understanding by solving a problem.

Convert a complex Map, including nested Maps and Objects, into a deep Object structure. Problem

javascript
/**
* Converts a Map with potentially nested Maps and Objects into a deep Object.
* @param {Map} map - The Map to convert.
* @return {Object} - The resulting deep Object.
*/
function theMapObjectAlchemist(map) {
  // > > > 👉 Write code here 👈 < < <
}

const complexMap = new Map([
  ['key1', 'value1'],
  ['nestedMap', new Map([['nestedKey', 'nestedValue']])],
  ['deepNestedMap', new Map([
      ['deepKey', new Map([['deepestKey', 'deepestValue']])]
  ])]
]);

console.log(theMapObjectAlchemist(complexMap));
// Expected Output: 👇
// {
//   key1: "value1",
//   nestedMap: {nestedKey: "nestedValue"},
//   deepNestedMap: {deepKey: {deepestKey: "deepestValue"}}
// }
Problem Statement

Please attempt before seeing the Answer:

Solution
javascript
function theMapObjectAlchemist(map) {
  const obj = {};
  for (let [key, value] of map) {
      if (value instanceof Map) {
          obj[key] = theMapObjectAlchemist(value);
      } else {
          obj[key] = value;
      }
  }
  return obj;
}
Solution Code

Explanation:

  • The theMapObjectAlchemist function iterates over the Map entries using a for...of loop. If a value is an instance of Map, it recursively calls itself, ensuring nested Maps are converted. For other values, it assigns them directly to the corresponding key in the object. This recursive approach allows for deep conversion, handling multiple levels of nested Maps.

With these techniques and tips, you can confidently handle Map & Object conversions in JavaScript.

"Why was the JavaScript Map sad? It missed its key to happiness!" 😀

Keep your key to happiness, and keep coding! 🚀👨‍💻

Contact

Feel free to reach out!