Performance comparison between Javascript Object and Map/Set for key lookup

I decided to experiment with the performance of JavaScript Object, Map, and Set when it comes to accessing keys. I tested the following three code snippets on JSBEN.CH.

Objects

const object = {};

for (let i = 0; i < 10000; ++i) {
    object[`key_${i}`] = 1;
}

let result = 0;
  
for (let i = 0; i < 10000; ++i) {
    result += object[`key_${i}`];
}

Maps

const map = new Map();

for (let i = 0; i < 10000; ++i) {
    map.set(`key_${i}`, 1);
}

let result = 0;

for (let i = 0; i < 10000; ++i) {
    result += map.get(`key_${i}`);
}

Sets

const set = new Set();

for (let i = 0; i < 10000; ++i) {
    set.add(`key_${i}`);
}

let result = 0;

for (let i = 0; i < 10000; ++i) {
    result += set.has(`key_${i}`);
}

Upon inspecting the results from the test link, it appears that while Map and Set display similar performance, Objects consistently perform slower in comparison. What could be causing this discrepancy where Objects are less efficient than Map or Set for basic key access operations?

Edit 1: Not only is accessing keys slower with Object, but setting keys is also shown to be slower than with Map or Set.

Answer №1

It's risky to rely solely on relative numbers when analyzing performance. Here are some absolute values from tests run on NodeJS v14.14.0 with an Intel 8350U processor:

Iterations Object write Object read Map write Map read
100 0ms 0ms 0ms 0ms
1,000 3ms 1ms 0ms 0ms
10,000 7ms 4ms 8ms 1ms
1,000,000 1222ms 527ms 632ms 542ms

Comparing objects and maps for 10,000 iterations shows just a 1-millisecond difference in the test results, which is within the margin of error. Therefore, no definitive conclusion can be drawn based on this test data as the results appear random.

For 1 million iterations, map writes outperform object writes significantly, while read performance remains similar between the two. Despite the slower object writes, reaching one million writes/s suggests that this aspect may not likely be the bottleneck in your application.

To understand the underlying processes better, examining the engine's bytecode by running node --print-code would provide valuable insights. An analysis reveals:

  1. If an object is constructed using Object.create(null) without a prototype, there is minimal impact on performance, indicating that prototype lookup does not affect overall efficiency.

  2. After the 20th iteration, V8 switches to using dictionary_map as the internal representation for objects, essentially pitting one hash map against another hashmap (accessible via node --allow-natives-syntax and executing %DebugPrint(object)).

Below is the benchmark code used for these tests:

function benchmark(TIMES) {  
  console.log("BENCHMARK ", TIMES);

  const object = Object.create(null);

    let start = Date.now();
    for (let i = 0; i < TIMES; ++i) {
        object[`key_${i}`] = 1;
    }

    console.log("Object write took", Date.now() - start);
    start = Date.now();

    let result = 0;
  
    for (let i = 0; i < TIMES; ++i) {
      result += object[`key_${i}`];
    }

    console.log("Object read took", Date.now() - start);
    start = Date.now();

  


  const map = new Map();
  
  for (let i = 0; i < TIMES; ++i) {
    map.set(`key_${i}`, 1);
  }
  
  console.log("Map write took", Date.now() - start);
  start = Date.now();

  result = 0;
  
  for (let i = 0; i < TIMES; ++i) {
    result += map.get(`key_${i}`);
  }

  console.log("Map read took", Date.now() - start);

}

benchmark(100);
benchmark(1_000);
benchmark(10_000);
benchmark(1_000_000);

In summary:

  • Opt for Maps for dictionaries with numerous varied keys that change frequently, as they slightly outperform objects internally represented as hash tables.
  • Choose Objects for scenarios involving a small number of keys with frequent access, as Objects offer faster processing due to inline caching, hidden classes with fixed memory layout, etc.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Learn how to display every ASCII or EBCDIC character once radio buttons have been selected

I'm currently working on a simple website that requires the user to input a minimum of 256 characters, choose between ASCII or EBCDIC for conversion, and then click the submit button (Run) to display the final converted result on the page. However, I& ...

It seems that there is a null value being returned in the midst of the

I have developed a model using express. While setting this in one function, it returns null in another function, forcing me to use return. What is the proper method to handle this situation? const Seat = function(seat) { this.seat = seat.seat; this. ...

A discrepancy has arisen as the value within the array structure is being altered

I am facing an issue with the array structure of an object in my Angular front-end code. When I add values to the array based on selection, the object looks like this: todayRates: 10 yesterdayRates: 5 to: Array(1) 0: [3] length: 1 __proto__: Array(0) __pro ...

Employing JavaScript for fading divs in and out sequentially

Hey there! I'm currently struggling with implementing transitions for my tool tips. Any assistance would be greatly appreciated! I am looking to have my "fader" divs fade in and out on click of a button, with each transition lasting 5 seconds. It&apo ...

Modifying the disabled attribute of an input tag upon button click in Angular 2

I am currently working on a function in Angular 2 where I want to toggle the disabled attribute of an input tag upon button click. Right now, I can disable it once but I am looking to make it switch back and forth dynamically. Below is the HTML template c ...

What is the correct way to start a typed Object in TypeScript/Angular?

As I delve into the world of Angular and TypeScript, I am faced with a dilemma regarding how to initialize an object before receiving data from an API request. Take for instance my model: //order.model.ts export class Order { constructor(public id: num ...

Creating a Python server for an Angularjs application and capturing user input

Can you offer me some assistance, whether it's just a hint or a useful tip that could improve my current approach? I have created a series of forms using HTML and AngularJS. Each form collects input data from users, which is then stored in a JSON str ...

Performance issues with Datatables server side processing

Utilizing Datatables server-side processing with PHP, JQuery, Ajax, and SQL Server database, I encountered slow performance in features such as pagination and search. Despite working with moderate data, there is a delay of over 40 seconds when using the se ...

A pale tooltip with a light arrow appearing against a soft white backdrop

Can someone help me figure out how to display a white tooltip with a white arrow? I've tried to implement it using the code below, but the white color is not visible against the background. Any suggestions on making it stand out? https://i.sstatic.ne ...

Retrieve information from an external JSON file and display it in a jstree

I am trying to pass JSON data to a jstree object from an external file. The code snippet I have does not seem to be working properly. <script> $.jstree.defaults.core.themes.responsive = true; $('#frmt').jstree({ plugins: [" ...

The ng-if directive in AngularJS seems to be malfunctioning

Could someone please help me understand why my "Voted:" checkbox is not controlling the ng-if directive? Strangely enough, the "Keep HTML" checkbox is working fine. <p> <li ng-repeat="x in info"> {{x.name}} Voted: <input type="c ...

Hiding the style tag in the head section of a Laravel-Vue.js application with Vue.js

Currently, I am working on a Laravel-Vue.js application. I have noticed that when Vue.js renders CSS, it appends some style tags in the HTML head as shown in the image below. Is there a way to hide these tags? My initial thought is that it can be achieved ...

How can I efficiently utilize HTML/CSS/JS to float items and create a grid that accommodates expandable items while minimizing wasted space?

After meticulously configuring a basic grid of divs using float, I've encountered an issue. When expanding an item in the right-hand column, the layout shifts awkwardly. My goal is to have boxes A and B seamlessly move up to fill the empty space, whi ...

The random quote generator or current tweet quote feature is malfunctioning

I am having trouble with a jQuery on click function that is not working to tweet the current quote. I am working on building a random quote machine and tweeting the current quote is essential. Despite successfully implementing the JSON API, I cannot seem t ...

Tips for achieving expansion of solely the clicked item and not the whole row

I am trying to create a card that contains a cocktail recipe. The card initially displays just the title, and when you click on a button, it should expand to show the full menu and description. The issue I'm facing is that when I click on one element, ...

Extract key/value pairs from a JSON array by eliminating any HTML tags

I have a JSON array payload that I need to break down into a separate object for downstream processing. The payload is flexible and may contain multiple nested levels in the JSON array, but the first level will always include an id field as the unique ide ...

Tips on assigning a data-id attribute

After a click event, I am attempting to dynamically set the data-id and/or value of a span using my JavaScript file. <span id="test"></span> Here is an example of the JavaScript code: nextLink: function(event) { $('#test').val ...

What is causing the local storage to not persist after refreshing the page?

Even after a browser refresh, the button text 'completed' should remain intact depending on whether the variable item is true (after the button click). I have experimented with Chrome and believe the issue is not related to the browser. <temp ...

JavaScript - Matching overlapping time intervals

Struggling to develop a custom filter using Javascript, I aim to determine if two time ranges in millisecond getTime() format match. The first time range is retrieved from an object while the second comes from user input for filtering. Currently, my code c ...

Failure to trigger Summernote's OnImageUpload function

After transitioning to the latest version of Summernote, which is Version 7, I encountered a problem with the image upload functionality. Despite specifying the line onImageUpload: function(files) {sendFile(files[0]);}, it seems that this code is not being ...