An Interest In:
Web News this Week
- April 24, 2024
- April 23, 2024
- April 22, 2024
- April 21, 2024
- April 20, 2024
- April 19, 2024
- April 18, 2024
Why to use Maps over Objects in JS ?
In JavaScript, an object is a standalone entity, with properties and type.
Compare it with a cup, for example. A cup is an object, with properties. A cup has color, design, weight, and the material it is made of, etc.
Table Of Contents
- Problems I faced while working with objects
- Solution: Maps Data Structure
- Comparison: Objects and Maps
- Practical Example
- Problems in Maps
- Conclusion
1. Problems I faced while working with objects:
Only string or symbol could be used as key.
- Objects have a limitation that their keys have to be strings
const names = { 1: 'One', 2: 'Two', }; Object.keys(names); // => ['1', '2']
- The numbers
1
and2
are keys in the names object. Later, when the objects keys are accessed, it turns out that thenumbers were converted to strings
. - Implicit conversion of keys is tricky because you
lose the consistency of the types.
No proper helper methods to work with objects.
- In order to find the length of the object we need to either use
Object.keys()
orObject.values()
and then find the length by accessing.length
on the array returned. - Similarly to iterate over it we have to use the same methods above to perform an iteration over the object.
- In order to find the length of the object we need to either use
Own object properties might collide with property keys inherited from the prototype (e.g. toString, constructor, etc).
- Any object inherits properties from its prototype object.
- The accidentally overwritten property inherited from the prototype is dangerous. Lets study such a dangerous situation.
- Lets overwrite the toString() property in an object actor:
const actor = { name: 'Harrison Ford', toString: 'Actor: Harrison Ford' /* this will cause a problem since we are overriding the toString method of the prototype chain */ };
Deleting keys causes problem in large objects.
- Using delete causes various forms and magnitudes of a slowdown in many situations, because it tends to make things more complicated, forcing the engine (any engine) to perform more checks and/or fall off various fast paths.
2. Solution: Using Maps Data Structure
Maps is a collection of keyed data items, just like an object. But the main difference is that Map allows keys of any type.
Methods and properties are:
new Map()
creates the map.map.set(key, value)
stores the value by the key.map.get(key)
returns the value by the key, undefined if the key doesnt exist in map.map.has(key)
returns true if the key exists, false otherwise.map.delete(key)
removes the value by the key.map.clear()
removes everything from the map.map.size
returns the current element count.
Code:
let map = new Map();map.set('1', 'str1'); // a string keymap.set(1, 'num1'); // a numeric keymap.set(true, 'bool1'); // a boolean key// remember the regular object? it would convert keys to string// Map keeps the type, so these two are different:alert( map.get(1) ); // 'num1'alert( map.get('1') ); // 'str1'alert( map.size ); // 3
Maps have useful and intuitive helper methods which are used to perform different operations.
3. Comparison: Objects and Maps
Parameters | Object | Maps |
---|---|---|
Accidental Keys | An object has a prototype, so it contains default keys that could collide with your own keys if you're not careful. | A Map does not contain any keys by default. It only contains what is explicitly put into it. |
Key Types | The keys of an object must be either a String or a Symbol. | A Map's keys can be any value (including functions, objects, or any primitive). |
Size | The number of items in an object must be determined manually. | The number of items in a Map is easily retrieved from its size property. |
Performance | Not optimized for frequent additions and removals of key-value pairs. | Performs better in scenarios involving frequent additions and removals of key-value pairs. |
4. Practical Example
Let's take an example of implementing select all functionality.
const selectedItems = {}; // we will use object here for quick lookup since its search is O(1)// adding item into selectedItemsselectedItems['image/png'] = true selectedItems['text/html'] = true// removing item from selectedItemsselectedItems['application/pdf'] = false
The code seems simple, but if you notice we are not deleting the key here we are setting it to false.
So in order to change the header selection state either from partial
to complete
or vice versa.We need to traverse over the object and detect false and true values.
It would have been easy if we could have deleted items from an object and then had checked the length of the object to determine if the current state is partial
or complete
.
But delete has performance issues in our V8 engine especially when we want to do multiple deletions of keys.
Maps comes to the rescue, map has delete functionality as well as functionality to return size, unlike object where we need to convert to array and then find the length of it. All without causing performance bottleneck.
const selectedItems = new Map()// adding item into selectedItemsselectedItems.set('image/png') selectedItems.set('text/html')// removing item from selectedItemsselectedItems.delete('application/pdf')
One of the solutions was to set selectionItems to {}
when we want to remove all the selected items, but that is not a scalable solution in certain situations.
When we do pagination in a table we have scenarios where select-all
is performed to items specific to the current page and not on the items of the next or previous page.
In this case, if we set selectedItems = {}
it will reset all the values, which is an incorrect solution.
Hence, maps are more scalable solution since it does not face any problem with respect to the deletion of the key.
5. Problems in Maps
Maps is not here to replace objects
- If we are only using string-based keys and need maximum read performance, then objects might be a better choice.
- This is because Javascript engines compile objects down to C++ classes in the background, and the access path for properties is much faster than a function call for Map().get().
- Adding or removing a property causes the shape of the class to change and the backing class to be re-compiled, which is why using an object as a dictionary with lots of additions and deletions is very slow, but reads of existing keys without changing the object are very fast.
Maps are not serializable
- Maps does not have native support for serialization or parsing
- Redux does not recommend using non-serializable data structures, since it can break the working of dev-tools and also will cause problems in rendering updates as expected: https://redux.js.org/style-guide/style-guide#do-not-put-non-serializable-values-in-state-or-actions
6. Conclusion
In review, while we will still rely heavily on JavaScript objects to do the job of holding structured data, they have some clear limitations
These limitations are solved by maps. Moreover, maps provide benefits like being iterators and allowing easy size look-up.
Objects are not good for information thats continually updated, looped over, altered, or sorted. In those cases, use maps.
In conclusion, use maps with a purpose. Think of maps and objects similar to how let and const are used for our variables.
Original Link: https://dev.to/faisalpathan/why-to-use-map-over-object-in-js-306m
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To