How to Convert Map To Object in Javascript


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)
// 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 (Real World Application)
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"}

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

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

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' } }
  • 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' }
  • 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"}

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

Its 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 (Incorrectly using JSON.stringify() on map)
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"}'

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 (Optimizing Serialization for Large Sets using Chunking)
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" }
  • 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 (Optimizing Serialization for Large Sets using Chunking)
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" }
  • 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):

Javascript (Web Worker Script `worker.js`)
// 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);
};

Then, in your main script:

Javascript (Main Script `worker.js`)
// 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]);
}
  • 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.

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"}}
// }
Please attempt before seeing the Answer:
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;
}

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! ๐Ÿš€๐Ÿ‘จโ€๐Ÿ’ป

Scroll to Top