Exploring the mechanics behind ES6 Map shims

From what I've gathered from the documentation (here and here), it seems that having a reference to the memory address is necessary for the operation to work:

const foo = {};
const map = new Map();
map.set(foo,'123');  // This action requires knowledge of the memory address of `foo`. Otherwise, any other method would involve converting `foo` into a string.

This limitation exists because keys in JavaScript objects {} can only be strings (at least in ES5).

However, there appears to be a shim available for Map: https://github.com/zloirock/core-js#map. I attempted to go through the source code but found it too abstracted (internally, it utilizes strong collection which further imports 10 more files)

Question

Please respond to any of the following queries

  • Is there a straightforward method to achieve this without involving string conversion?
  • Could it potentially alter foo to save a string within it and then utilize that as the key?
  • Perhaps I'm misunderstanding the documentation entirely?

Answer №1

When considering different approaches, two methods stand out. Firstly, you could utilize an array of keys and search through it sequentially:

Map1 = {
    keys: [],
    values: [],
};

Map1.set = function(key, val) {
    var k = this.keys.indexOf(key);
    if (k < 0)
        this.keys[k = this.keys.length] = key;
    this.values[k] = val;
};

Map1.get = function(key) {
    return this.values[this.keys.indexOf(key)];
};


foo = {};
bar = {};

Map1.set(foo, 'xxx');
Map1.set(bar, 'yyy');

document.write(Map1.get(foo) + Map1.get(bar) + "<br>")

The second approach involves assigning a unique "key" identifier to an object used as a key:

Map2 = {
    uid: 0,
    values: {}
};

Map2.set = function(key, val) {
    key = typeof key === 'object'
        ? (key.__uid = key.__uid || ++this.uid)
        : String(key);
    this.values[key] = val;
};

Map2.get = function(key) {
    key = typeof key === 'object'
        ? key.__uid
        : String(key);
    return this.values[key];
};


foo = {};
bar = {};

Map2.set(foo, 'xxx');
Map2.set(bar, 'yyy');

document.write(Map2.get(foo) + Map2.get(bar) + "<br>")

Unlike the first method, the second one has a time complexity of O(1). To enhance accuracy, consider making uid non-writable/enumerable. Additionally, ensure each Map has its own designated "uid" property (easily implemented in the Map constructor).

Answer №2

To efficiently retrieve data from a collection, one can utilize an array for storage and implement a lookup operation in O(n) time complexity by iterating through the array with strict comparison. This approach differs from using a true hash function, which would provide O(1) lookup performance. An illustration of this concept is demonstrated below:

var myObj = {};

var someArray = [{}, {}, myObj, {}];

console.log(someArray.indexOf(myObj)); // returns 2

A more detailed implementation can be found in the following reference link: JavaScript HashTable Using Object Keys

function Map() {
    var keys = [], values = [];

    return {
        put: function (key, value) {
            var index = keys.indexOf(key);
            if(index == -1) {
                keys.push(key);
                values.push(value);
            }
            else {
                values[index] = value;
            }
        },
        get: function (key) {
            return values[keys.indexOf(key)];
        }
    };
}

Answer №3

Check out my polyfill solution here. I'm not promoting it, but I believe it's the simplest and most straightforward option available for learning and educational purposes. It utilizes a lookup table for keys and corresponding value tables.

var k = {}, j = [], m = document, z = NaN;
var m = new Map([
    [k, "foobar"], [j, -0xf], [m, true], [z, function(){}]
]);




Index      Key                 Value
##### ################    ################
0.    k ({})              "foobar"
1.    j ([])              -15
2.    m (Document)        true
3.    z (NaN)             function(){}

Each item is internally stored at a different index, following a similar approach to how browsers handle it. Some other polyfills store keys on objects themselves and manipulate internal methods, causing significant performance issues. My method aims to avoid such slowdowns by segregating items in memory locations.

The functionality of my polyfill relies on the distinct storage locations of javascript objects, hence why [] !== [] and indexOf works seamlessly on arrays of objects. They are unique entities in memory.

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

Get back a variety of substitutions

I have a variety of different text strings that I need to swap out on the client side. For example, let's say I need to replace "Red Apple" with "Orange Orange" and "Sad Cat" with "Happy Dog". I've been working on enhancing this particular ques ...

Utilize $stateParams to dynamically generate a title

When I click a link to our 'count' page, I can pass a router parameter with the following code: $state.go('count', {targetName: object.name}) The router is set up to recognize this parameter in the URL: url: '/count/:targetName& ...

Getting the content of a textarea within a v-for loop collection

Exploring this particular situation In a .vue file within the template <div v-for="(tweet, index) in tweets"> <div class="each_tweet"> <textarea v-on:keyup="typing(index)" placeholder="Share your thoughts">{{ tweet.c ...

"Turn a blind eye to Restangular's setRequestInterceptor just this

When setting up my application, I utilize Restangular.setRequestInterceptor() to trigger a function that displays a loading screen whenever a request is made with Restangular. Yet, there is a specific section in my application where I do not want this fun ...

What steps can I take to resolve this issue when encountering an error during npm install?

As a newcomer to programming, I am embarking on the creation of a Discord bot using node and discord.js. My current hurdle involves the installation of a library named canvas, which seems to be causing issues. After developing and testing my application o ...

Instructions on utilizing the CSSStyleSheet.insertRule() method for modifying a :root attribute

Is it possible to dynamically set the background color of the :root CSS property in an HTML file based on a hash present in the URL? The code provided does change the background color, but unfortunately, the hash value doesn't persist as users navigat ...

Mongoose fails to save due to an error stating "undefined id"

Having some trouble with the Mongoose save function... In my user model file: const mongoose = require('mongoose'); const Schema = mongoose.Schema; const User = mongoose.model('User', { name: Schema.Types.Mixed, gender: String, ...

Javascript Calculator with Dual Input Fields

I have been given a task to create a calculator by tomorrow using Javascript. Unfortunately, I am currently taking a distance course and Javascript has just been introduced in this assignment. While I am familiar with HTML and CSS, Javascript is something ...

An Angular application running on an Azure App Service experiences crashes exclusively when accessed through the Chrome browser

My webapi/angular site is hosted on the same Azure app service, with authentication token and other APIs located at /site/api and the angular app at /site/app. Everything works fine on our staging environment, which is a Windows 2012 VM with IIS 7. The an ...

To ensure that new tabs are opened directly within jQuery UI tabs, the tab should be created within the jQuery UI tabs interface

I have integrated jquery-UI to create a dynamic Tab panel. When I click on the "Add Tab" button, a new tab is created. However, the new tab does not open automatically. It only opens when clicked on. $(function() { var tabTitle = $( ...

How to pass a prop from Nuxt.js to a component's inner element

I've created a basic component: <template> <div id="search__index_search-form"> <input :bar-id="barId" @keyup.enter="findBars()" type="text" :value="keyword" @input="updateKeyword" placeholder="Search for a b ...

VueJS Vuetify automatically centers default content

Vue cli version @ 5.0.6 | Vuetify version: [email protected] I have been utilizing Vue.js and Vuetify for some time now, and I can't shake the feeling that not all Vue.js/Vuetify components default to centered alignment. I recently initialized a ...

Creative Solution for Implementing a Type Parameter in a Generic

Within my codebase, there exists a crucial interface named DatabaseEngine. This interface utilizes a single type parameter known as ResultType. This particular type parameter serves as the interface for the query result dictated by the specific database dr ...

What is the best way to show a div after successfully sending a post value using AJAX?

How do I show this specific div after a successful AJAX post? This is what I want to display: <div class="love" id="love_0" style="border-radius: 3px; padding: 8px; border: 1px solid #ccc; right: 13px; background: #fff; top: 13px;"> <a class ...

Using react hooks, I am refreshing the product image by replacing it with the thumbnail image

I'm currently working on an e-commerce platform that resembles Amazon. In the product detail page, I want the right side image to update when I click on a thumbnail image on the left side. The issue I'm facing is that upon first loading, the def ...

Having issues with displaying options in Select2 within a Vue Component?

I have successfully created a Vue component that generates options for a select dropdown as shown below: <select ref="subdomain_id" name="subdomain_id" id="newEvidenceSubdomain" class="form-control" :class=&qu ...

How to detect the Back Button or Forward Button events in a single-page application

Currently, I am developing a single-page application that utilizes ASP.NET MVC, Backbone.js, and JQuery. My task involves capturing the browser's back and forward button events for breadcrumb implementation. I previously attempted to use the hashchan ...

Zod vow denial: ZodError consistently delivers an empty array

My goal is to validate data received from the backend following a specific TypeScript structure. export interface Booking { locationId: string; bookingId: number; spotId: string; from: string; to: string; status: "pending" | "con ...

What is the best method for passing a JavaScript object to PHP using Ajax?

I have looked into similar questions like this and this, but none of them have helped me solve my issue. When I check the console log for my data, it displays the following: Object["row_LM#00000010", "row_LM#00000002", "row_LM#00000009", "row_LM#00000008" ...

Angular's interactive checkboxes and dropdown menus provide a dynamic user experience

There is a global List array where data from an API is passed in the OnInit method. List: any; visibility:any; Status:any; ngOnInit(): void { let param = {...}; this.Service.getUser(param).subscribe(result => { this.List = result['response ...