Skip to content

Instantly share code, notes, and snippets.

@rezavai92
Created June 1, 2021 13:29
Show Gist options
  • Save rezavai92/d5adcbcd929b92e654d492a6d6b1e06e to your computer and use it in GitHub Desktop.
Save rezavai92/d5adcbcd929b92e654d492a6d6b1e06e to your computer and use it in GitHub Desktop.

Object as Map in Javascript, No Alternative?

In different languages including javascript , "map" is introduced as a higher order function that uses another function in order to transform any structure like array to a certain form . But this not the same case when we talk about the "Map" structure. Map is a non-linear data structure we often have to use to fufill some specific purpose in certain use cases . Many programming languages provide a built in support for using map in different names. For example , in python this is "dictionary" that serves as map. Unfortunately Javascript had nothing called "Map" before Ecmascript2015 had released,which compelled the developers growing the habit of using "object" as "Map" from the very beginning. This blog assumes that you already know javascript (and definitely familliar with Object) and have been using Object as map without giving a second thought like many other programmers out there . In general, there is no issue in treating object as map and this blog is not written for discouraging you from doing so. Rather i would like to show some anomalies around using js object as map in certain use cases and how to avoid those in your next program .

javascript object facillitates the tasks of a programmer in many ways. First of all, you don't have to create a class in order to leverage the power of an object anytime in your program. For example , if you have to send a groupd of data to the server in a single request, you can simply create an object with the relevant properties having those values .It could have been a cumbersome task in other programming languages where creating a class is a mandatory thing for using it's object. For example

let person = { name : "reza",
               age : 25,
               occupation : "student"
            }

We can see that, person is an object having "name", "age" and "occupations" as properties. We can know the value of each property in jus one go.

console.log(person.name) //  returns  "reza"
console.log(person.age) // returns 25

using object.property is a common approach in many programming languages to access the object's properties. Javascript provides a different way to access the properties as if it saves them in "key-value" pairs . console.log(person["name"] ) // returns "reza"

with this much flexibility around js object, we usually treat it as "Map" whenever we need to use map like structure. javascript ,by its nature is a tricky language that if you are not curious enough to see it's anomalous behavior , it will keep you in peace [but life seems hell when it starts behaving anomalous]. we will now use the aforementioned example to show some inconsistencies around using js object as Map.

 console.log("name" in person) // true 
 console.log("address" in person)  // false . person has no such property.
 console.log("toString" in person) // true . but why? 

First two examples worked as expected, but in third one, despite "person" object's having no key like "toString" , it returned true . This is so weird ,right ?

Let's now try to understand the reason behind this inconsistency ? the "in" operator checks if a given property is valid in an object . Javascript is actually a prototype based language that every object has a thing (object actually) like "prototype" which keeps the record of all 'its' inherited properties from the "master/parent" Object/Class. This is how inheritance is ensured in js object via prototype chaining . you can console.dir("any object") in your browser's console to see the protoype chaining .

It is clear that, every object in javascript inherits everything from a "master" Object .For this, we can use a bunch of alien methods for string,arrays without even defining them in our code . "toString" is such a method every object inherits from the master object. Even though "person" object has no key like "toString", it is defined in it's master object . I guess, Now you have got the point why it returned "true" in last example.

Is there any way to get rid of this inconsistency from our object. The answer is yes . you can simply tell javascript that my object will not have any prototype. if you create your object the following way

    Object.create(null)

the created object will have no prototype as well as those "alien" properties and methods in it . Let's elaborate a bit to understand this.

    let person = Object.create(null)
    console.dir(person) // it will show no properties in it so far including  prototype

The created object will not inherit anything from the master "Object" unlike the previous one. to check, console.dir it in your browser console. Now let's try to add the properties we want to see in person object.

    person.name  = "reza"
    person.age = 25
    console.dir(person) // it will just show name and age as property.

Now if you check anything which is not present in current object, it will show false. Wohooo!

There are other issues in treating object as Map . For example, every property of an object is supposed to be a string. So ,in such use cases where conversion from "key" to "string" is difficult (in case of object and function) , you cannot use object as Map . No worries!! Javascript came up with a new structure called Map (released with Ecmascript 2015) which exactly fulfills our purpose. Why not using this?

    let person = new Map()
    person.set("name","reza")
    person.set("age",25)
    console.has("name") // returns true
    console.has("age")  // returns true
    console.has("toString")

At first we created the person map. Then, we set two properties for person (name and age) . we then checked the person Map with some keys which gave us the expected result. Remember one thing, if you try to use "in" operator to see anything is valid inside map, you will see some inconsistencies. for example ,

      console.log("toString" in person) // still returns true

We will never use "in" operator to check something inside Map. Because , it rather checks things not in the map, but in the object itself. It is obvious that, person itself is an object created in reference of Map class . as a result, "toString" and other keys from prototype will still be valid in person object. but if you check them with "has" method, they will be invalid and return false.

we can also access the value of the properties/keys with "get" method .

    console.log(person.get("name") ) // returns "reza"

Here are other advantages of using Map :

  • It preserves the order of the keys we set while it is not guaranteed in case of object.
  • We can easily find the size of map with size method while it's not that straightforward in object.

Last but not the least, Map is not a replacement for using object as map. You can still treat our sweet "object" as map following certain rules. For example, Object.keys("myobject") will return only the keys of myobject. Another alternative to using "in" operator is "hasOwnProperty" method, as it will not take inherited properties into consideration while checking .To sum up, I just tried to shed some light on different aspects of Object and Map .Its up to you which one you will use in different use cases. Happy Coding!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment