7 Answers
They both behave differently when a object referenced by their keys/values gets deleted. Lets take the below example code:
var map = new Map(); var weakmap = new WeakMap(); (function(){ var a = {x: 12}; var b = {y: 12}; map.set(a, 1); weakmap.set(b, 2); })()
The above IIFE is executed there is no way we can reference
{x: 12}
and
{y: 12}
anymore. Garbage collector goes ahead and deletes the key b pointer from “WeakMap” and also removes
{y: 12}
from memory. But in case of “Map”, the garbage collector doesn’t remove a pointer from “Map” and also doesn’t remove
{x: 12}
from memory.
Summary: WeakMap allows garbage collector to do its task but not Map.
References: http://qnimate.com/difference-between-map-and-weakmap-in-javascript/
-
20Why is it not removed from memory? Because you can still reference it!
map.entries().next().value // [{x:12}, 1]
May 29, 2015 at 2:42 - 8It’s not a self invoked function. It’s an immediately invoked function expression. benalman.com/news/2010/11/… Jul 21, 2015 at 14:53
- then what’s a difference between weakmap and object Aug 12, 2016 at 15:37
-
2@MuhammadUmer: object can only have string ‘keys’, while
WeakMap
can only have non-primitive keys (no strings or numbers or
Symbol
s as keys, only arrays, objects, other maps, etc.). Aug 28, 2016 at 5:41 -
2@nnnnnn Yes that’s the difference, it’s still in the
Map
but not in the
WeakMap
Aug 2, 2017 at 9:58
Maybe the next explanation will be more clear for someone.
var k1 = {a: 1}; var k2 = {b: 2}; var map = new Map(); var wm = new WeakMap(); map.set(k1, 'k1'); wm.set(k2, 'k2'); k1 = null; map.forEach(function (val, key) { console.log(key, val); // k1 {a: 1} }); k2 = null; wm.get(k2); // undefined
As you see, after removing
k1
key from the memory we can still access it inside the map. At the same time removing
k2
key of WeakMap removes it from
wm
as well by reference.
That’s why WeakMap hasn’t enumerable methods like forEach, because there is no such thing as list of WeakMap keys, they are just references to another objects.
- 14in the last line, of course, wm.get(null) will be undefined.– DaNeShAug 12, 2016 at 21:39
- 9Better answer than copying and pasting from the mozilla site, kudos. Dec 4, 2016 at 13:03
-
3in the
forEach
,
(key, val)
should be actually be
(val, key)
Jan 20, 2017 at 2:11 - 3unbelievable how an example that makes no sense get so many upvotes Jul 18, 2020 at 22:01
- 1map.get(k1) would also return null Sep 5, 2022 at 15:03
From the very same page, section “Why Weak Map?”:
The experienced JavaScript programmer will notice that this API could be implemented in JavaScript with two arrays (one for keys, one for values) shared by the 4 API methods. Such an implementation would have two main inconveniences. The first one is an O(n) search (n being the number of keys in the map). The second one is a memory leak issue. With manually written maps, the array of keys would keep references to key objects, preventing them from being garbage collected. In native WeakMaps, references to key objects are held “weakly”, which means that they do not prevent garbage collection in case there would be no other reference to the object.
Because of references being weak, WeakMap keys are not enumerable (i.e. there is no method giving you a list of the keys). If they were, the list would depend on the state of garbage collection, introducing non-determinism.
[And that’s why they have no
size
property as well]
If you want to have a list of keys, you should maintain it yourself. There is also an ECMAScript proposal aiming at introducing simple sets and maps which would not use weak references and would be enumerable.
‐ which would be the “normal”
Map
s. Not mentioned at MDN, but in the harmony proposal, those also have
items
,
keys
and
values
generator methods and implement the
Iterator
interface.
-
so
new Map().get(x)
has about the same look-up time as reading a property from a plain object? May 5, 2018 at 18:41 - 1@AlexanderMills I don’t see what this has to do with the question, but here is some data. In general, yes they are similar, and you should use the appropriate one. May 5, 2018 at 18:48
- So my understanding is Map maintains an internal array to persist its key because of that array. Garbage collector is not able to refrain the reference. In WeekMap, it doesnt have a array where keys maintained so key with no reference can be garbage collected. May 17, 2018 at 12:03
-
@MohanRam A
WeakMap
still has an array (or other collection) of entries, it just tells the garbage collector that those are weak references. May 17, 2018 at 12:41 - 1@MohanRam Check the second paragraph in the first quote in the answer May 17, 2018 at 12:45
Another difference (source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap):
Keys of WeakMaps are of the type Object only. Primitive data types as keys are not allowed (e.g. a Symbol can’t be a WeakMap key).
Nor can a string, number, or boolean be used as a
WeakMap
key. A
Map
can use primitive values for keys.
w = new WeakMap; w.set('a', 'b'); // Uncaught TypeError: Invalid value used as weak map key m = new Map m.set('a', 'b'); // Works
- 7In case anyone wonders: I can imagine the reason behind this is: you can’t keep or pass references to primitive types. So the key in a WeakMap would be its only reference, ever. That way garbage collection wouldn’t be possible. I don’t know if weak references are impossible or just don’t make sense. But either way the key needs to be something that can be referenced weakly. Jan 8, 2016 at 14:00
From Javascript.info
Map — If we use an object as the key in a regular Map, then while the Map exists, that object exists as well. It occupies memory and may not be garbage collected.
let john = { name: "John" }; let array = [ john ]; john = null; // overwrite the reference // john is stored inside the array, so it won't be garbage-collected // we can get it as array[0]
Similar to that, if we use an object as the key in a regular Map, then while the Map exists, that object exists as well. It occupies memory and may not be garbage collected
let john = { name: "John" }; let map = new Map(); map.set(john, "..."); john = null; // overwrite the reference // john is stored inside the map, // we can get it by using map.keys()
WeakMap — Now, if we use an object as the key in it, and there are no other references to that object – it will be removed from memory (and from the map) automatically.
let john = { name: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); john = null; // overwrite the reference // john is removed from memory!
WeakMap
keys must be objects, not primitive values.
let weakMap = new WeakMap(); let obj = {}; weakMap.set(obj, "ok"); // works fine (object key) // can't use a string as the key weakMap.set("test", "Not ok"); // Error, because "test" is not an object
Why????
Let’s see below example.
let user = { name: "User" }; let map = new Map(); map.set(user, "..."); user = null; // overwrite the reference // 'user' is stored inside the map, // We can get it by using map.keys()
If we use an object as the key in a regular
Map
, then while the
Map
exists, that object exists as well. It occupies memory and may not be garbage collected.
WeakMap
is fundamentally different in this aspect. It doesn’t prevent garbage-collection of key objects.
let user = { name: "User" }; let weakMap = new WeakMap(); weakMap.set(user, "..."); user = null; // overwrite the reference // 'user' is removed from memory!
if we use an object as the key in it, and there are no other references to that object – it will be removed from memory (and from the map) automatically.
WeakMap
does not support iteration and methods keys(), values(), entries(), so there’s no way to get all keys or values from it.
WeakMap has only the following methods:
- weakMap.get(key)
- weakMap.set(key, value)
- weakMap.delete(key)
- weakMap.has(key)
That is obvious as if an object has lost all other references (like ‘user’ in the code above), then it is to be garbage-collected automatically. But technically it’s not exactly specified when the cleanup happens.
The JavaScript engine decides that. It may choose to perform the memory cleanup immediately or to wait and do the cleaning later when more deletions happen. So, technically the current element count of a
WeakMap
is not known. The engine may have cleaned it up or not or did it partially. For that reason, methods that access all keys/values are not supported.
Note:- The main area of application for WeakMap is an additional data storage. Like caching an object until that object gets garbage collected.
WeapMap in javascript does not hold any keys or values, it just manipulates key value using a unique id and define a property to the key object.
because it define property to
key object
by method
Object.definePropert()
, key must not be primitive type.
and also because WeapMap does not contain actually key value pairs, we cannot get length property of weakmap.
and also manipulated value is assigned back to the key object, garbage collector easily can collect key if it in no use.
Sample code for implementation.
if(typeof WeapMap != undefined){ return; } (function(){ var WeapMap = function(){ this.__id = '__weakmap__'; } weakmap.set = function(key,value){ var pVal = key[this.__id]; if(pVal && pVal[0] == key){ pVal[1]=value; }else{ Object.defineProperty(key, this.__id, {value:[key,value]}); return this; } } window.WeakMap = WeakMap; })();
reference of implementation
- 1To be clear, this implementation only half works. It won’t allow using the same object as key in multiple weak maps. It also does not work for frozen objects. And of course, it leaks the mapping to anybody who has a reference to the object. The first can be fixed using symbols, but not the latter two. Jul 12, 2020 at 16:13
-
@AndreasRossberg In this implementation I have added hardcoded
id
, but this should be unique by using something Math.random and Date.now(), etc. And by adding this dynamic id, the first point can be solved. Could you please provide me a solution for the last two points. Jul 13, 2020 at 5:16 - The first problem is solved more elegantly by using symbols. The latter two cannot be solved within JS, which is why WeakMap has to be a primitive in the language. Jul 13, 2020 at 7:18
JavaScript provides many data structures for developers to choose from. Two of the most commonly used data structures in JavaScript are
Map
and
WeakMap
. Although both of these data structures have similar functionalities, there are some key differences that set them apart. In this article, we’ll explore these differences and help you choose the right data structure for your needs.
Understanding Maps
Maps are a type of data structure that allows developers to store key-value pairs. In other words, they allow you to associate values with keys in a way that’s easy to access and manipulate. Maps are similar to objects in JavaScript, but they have a few key differences. For example, Maps can use any value as a key, including objects and functions, whereas objects can only use strings or symbols as keys.
To create a Map, you can use the
Map()
constructor, like this:
const myMap = new Map();
You can also initialize a Map with key-value pairs using an array of arrays, like this:
const myMap = new Map([ ["key1", "value1"], ["key2", "value2"], ]);
Once you have a Map, you can add or update key-value pairs using the
set()
method, like this:
myMap.set("key3", "value3");
You can also retrieve values from a Map using the
get()
method, like this:
const value = myMap.get("key1");
Understanding WeakMaps
WeakMaps are similar to Maps in that they also allow you to store key-value pairs. However, they have some key differences that make them useful in different situations.
The most significant difference between WeakMaps and Maps is that WeakMaps only allow objects as keys, and those objects are held weakly. In other words, if there are no other references to an object used as a key in a WeakMap, that object will be garbage collected, and the corresponding value will be automatically removed from the WeakMap. This can be useful in situations where you want to associate data with an object that may be destroyed, like a DOM node.
To create a WeakMap, you can use the
WeakMap()
constructor, like this:
const myWeakMap = new WeakMap();
You can also initialize a WeakMap with key-value pairs using an object, like this:
const myObj = {}; const myWeakMap = new WeakMap([[myObj, "value"]]);
Once you have a WeakMap, you can add or update key-value pairs using the
set()
method, like this:
myWeakMap.set(myObj, "new value");
You can also retrieve values from a WeakMap using the
get()
method, like this:
const value = myWeakMap.get(myObj);
Differences Between Maps and WeakMaps
Now that we’ve covered the basics of Maps and WeakMaps, let’s explore the differences between these two data structures.
- Key Types: Maps can use any value as a key, including strings, numbers, objects, and functions. WeakMaps can only use objects as keys.
- Garbage Collection: Objects used as keys in WeakMaps are held weakly, which means they can be garbage collected if there are no other references to them. This can be useful for situations where you want to associate data with an object that may be destroyed, like a DOM node. Maps do not have this feature and will keep keys and values in memory until they are explicitly deleted.
-
Iteration: Maps can be iterated over using methods like
keys()
,
values()
, and
entries()
. WeakMaps do not have these methods because they are not enumerable. This means that you cannot iterate over a WeakMap to retrieve all of its keys or values. -
Size: Maps have a
size
property that returns the number of key-value pairs in the map. WeakMaps do not have a
size
property because the number of key-value pairs is not fixed and can change based on garbage collection. - Performance: WeakMaps have additional garbage collection overhead, so they can be slower than Maps. If performance is a concern, Maps may be a better choice.
When to Use Maps
Maps are a good choice when you need to store key-value pairs and want to use any type of value as a key. Maps are also a good choice when you need to iterate over the keys or values in a predictable order, or when you need to get the number of key-value pairs in the map.
When to Use WeakMaps
WeakMaps are a good choice when you need to associate data with an object that may be destroyed, like a DOM node. WeakMaps are also useful when you want to avoid memory leaks and do not need to iterate over the keys or values in the map.
Conclusion
By understanding these differences, you can choose the right data structure for your needs and build better, more efficient JavaScript applications.
- Trending Categories
- Data Structure
- Networking
- RDBMS
- Operating System
- Java
- MS Excel
- iOS
- HTML
- CSS
- Android
- Python
- C Programming
- C++
- C#
- MongoDB
- MySQL
- Javascript
- PHP
- Physics
- Chemistry
- Biology
- Mathematics
- English
- Economics
- Psychology
- Social Studies
- Fashion Studies
- Legal Studies
- Selected Reading
- UPSC IAS Exams Notes
- Developer’s Best Practices
- Questions and Answers
- Effective Resume Writing
- HR Interview Questions
- Computer Glossary
- Who is Who
What is the difference between Map and WeakMap in JavaScript?
Javascript
|
Map(0) {}
Map(1) { ‘info’ => { name: ‘Sam’, age: 36 } }
{ name: ‘Sam’, age: 36 }
check whether info is there or not – true
The no.of elements in a Map are 1
Map(0) {}
name- Sam
age- 36
WeakMap: In a Weak Map, every key can only be an object and function. It used to store weak object references. For better understanding, we take an example of WeakMap and its properties:
Example: This example shows the implementation of Map in Javascript.
Advantages of Map:
Map object provided by ES6. A key of a Map may occur once, which will be unique in the map’s collection. There are slight advantages to using a map rather than an object.
- Accidental Keys & Security: No default keys are stored, only contain what’s explicitly put into them. Because of that, it’s safe to use.
- Key Types & Order: It can be any value as a key function, object anything. And the order is straightforward way in the order of entry insertion.
- Size: Because of the size property a map can be easily retrieved.
- Performance: Any operation can be performed on math so easily in a better way.
- Serialization and parsing: We can create our own serialization and parsing support for Map by using JSON.stringify() and JSON.parse() methods.
Removing Elements
You can use the
clear()
and the
delete()
method to remove elements from a Map.
The
delete()
method returns
true
if a specified key/value pair exists and has been removed or else returns
false
. For example,
let map1 = new Map(); map1.set('info', {name: 'Jack', age: "26"}); // removing a particular element map1.delete('address'); // false console.log(map1); // Map {"info" => {name: "Jack", age: "26"}} map1.delete('info'); // true console.log(map1); // Map {}
The
clear()
method removes all key/value pairs from a Map object. For example,
let map1 = new Map(); map1.set('info', {name: 'Jack', age: "26"}); // removing all element map1.clear(); console.log(map1); // Map {}
Summary
WeakMap
is
Map
-like collection that allows only objects as keys and removes them together with associated value once they become inaccessible by other means.
WeakSet
is
Set
-like collection that stores only objects and removes them once they become inaccessible by other means.
Their main advantages are that they have weak reference to objects, so they can easily be removed by garbage collector.
That comes at the cost of not having support for
clear
,
size
,
keys
,
values
…
WeakMap
and
WeakSet
are used as “secondary” data structures in addition to the “primary” object storage. Once the object is removed from the primary storage, if it is only found as the key of
WeakMap
or in a
WeakSet
, it will be cleaned up automatically.
Lúc nào nên xài cái gì?
Không phải ngẫu nhiên mà Javascript ES6 bổ sung thêm WeakMap. Rõ ràng Map luôn có sự bất tiện khi sử dụng.
Rõ ràng có sự bất tiện khi sử dụng Map
Vấn đề memory có được dọn dẹp hay không đã là sự khác biệt map và weakmap. Vậy lúc nào ta nên dùng WeakMap?
- Đầu tiên, ta cần một Map để chứa key-value. Tuy nhiên thời gian sử dụng chỉ gói gọn trong một vài dòng code. Tính toán, mapping xong lại không xài tới Map nữa -> Ưu tiên sử dụng WeakMap.
- Keeping private data about a specific object and only giving access to it to people with a reference to the Map. A more ad-hoc approach is coming with the private-symbols proposal but that’s a long time from now. Đảm bảo an toàn cho dữ liệu, chỉ cho phép access đối với các đối tượng có tham chiếu và cần sử dụng tới WeakMap.
Chắc sẽ còn một vài trường hợp khác WeakMap trở nên hữu ích. Tui sẽ bổ sung cho mấy ông sau.
WeakMap
The first difference between
Map
and
WeakMap
is that keys must be objects, not primitive values:
Now, if we use an object as the key in it, and there are no other references to that object – it will be removed from memory (and from the map) automatically.
let john = { name: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); john = null; // overwrite the reference // john is removed from memory!
Compare it with the regular
Map
example above. Now if
john
only exists as the key of
WeakMap
– it will be automatically deleted from the map (and memory).
WeakMap
does not support iteration and methods
keys()
,
values()
,
entries()
, so there’s no way to get all keys or values from it.
WeakMap
has only the following methods:
Why such a limitation? That’s for technical reasons. If an object has lost all other references (like
john
in the code above), then it is to be garbage-collected automatically. But technically it’s not exactly specified when the cleanup happens.
The JavaScript engine decides that. It may choose to perform the memory cleanup immediately or to wait and do the cleaning later when more deletions happen. So, technically, the current element count of a
WeakMap
is not known. The engine may have cleaned it up or not, or did it partially. For that reason, methods that access all keys/values are not supported.
Now, where do we need such a data structure?
Định nghĩa
Map thì đã quá quen thuộc rồi
The
Map
object holds key-value pairs and remembers the original insertion order of the keys. Any value (both objects and primitive values) may be used as either a key or a value.Đối tượng
Map
lưu cặp key-value (khoá – giá trị) theo thứ tự chèn vào của khoá. Bất kỳ giá trị nào (cả đối tượng (objects) và primitive values) đều có thể sử dụng làm key hoặc value.
WeakMap thì bản thân bao gồm 2 chữ. Weak và Map, hẳn là phải có cái gì đó “yếu hơn” rồi.
The
WeakMap
object is a collection of key/value pairs in which the keys are weakly referenced. The keys must be objects and the values can be arbitrary values.
Đối tượng WeakMap
là collection của các cặp key/value với các key được tham chiếu yếu ớt. Các key phải là đối tượng và các value có thể là bất kỳ giá trị nào.
Cả Map và WeakMap đều cho phép lưu trữ theo kiểu key-value. Key và uniques và một loạt Value đi kèm. Tuy nhiên vẫn tồn tại một số sự khác biệt map và weakmap.
Weak không có nghĩa là yếu. Chỉ “lỏng lẻo” hơn một vài điểm thôi
Examples
Using WeakMap
const wm1 = new WeakMap(); const wm2 = new WeakMap(); const wm3 = new WeakMap(); const o1 = {}; const o2 = function () {}; const o3 = window; wm1.set(o1, 37); wm1.set(o2, "azerty"); wm2.set(o1, o2); // a value can be anything, including an object or a function wm2.set(o2, undefined); wm2.set(wm1, wm2); // keys and values can be any objects. Even WeakMaps! wm1.get(o2); // "azerty" wm2.get(o2); // undefined, because that is the set value wm2.get(o3); // undefined, because there is no key for o3 on wm2 wm1.has(o2); // true wm2.has(o2); // true (even if the value itself is 'undefined') wm2.has(o3); // false wm3.set(o1, 37); wm3.get(o1); // 37 wm1.has(o1); // true wm1.delete(o1); wm1.has(o1); // false
Implementing a WeakMap-like class with a .clear() method
class ClearableWeakMap { #wm; constructor(init) { this.#wm = new WeakMap(init); } clear() { this.#wm = new WeakMap(); } delete(k) { return this.#wm.delete(k); } get(k) { return this.#wm.get(k); } has(k) { return this.#wm.has(k); } set(k, v) { this.#wm.set(k, v); return this; } }
Emulating private members
Developers can use a
WeakMap
to associate private data to an object, with the following benefits:
-
Compared to a
Map
, a WeakMap does not hold strong references to the object used as the key, so the metadata shares the same lifetime as the object itself, avoiding memory leaks. -
Compared to using non-enumerable and/or
Symbol
properties, a WeakMap is external to the object and there is no way for user code to retrieve the metadata through reflective methods like
Object.getOwnPropertySymbols
. - Compared to a closure, the same WeakMap can be reused for all instances created from a constructor, making it more memory-efficient, and allows different instances of the same class to read the private members of each other.
let Thing; { const privateScope = new WeakMap(); let counter = 0; Thing = function () { this.someProperty = "foo"; privateScope.set(this, { hidden: ++counter, }); }; Thing.prototype.showPublic = function () { return this.someProperty; }; Thing.prototype.showPrivate = function () { return privateScope.get(this).hidden; }; } console.log(typeof privateScope); // "undefined" const thing = new Thing(); console.log(thing); // Thing {someProperty: "foo"} thing.showPublic(); // "foo" thing.showPrivate(); // 1
This is roughly equivalent to the following, using private fields:
class Thing { static #counter = 0; #hidden; constructor() { this.someProperty = "foo"; this.#hidden = ++Thing.#counter; } showPublic() { return this.someProperty; } showPrivate() { return this.#hidden; } } console.log(thing); // Thing {someProperty: "foo"} thing.showPublic(); // "foo" thing.showPrivate(); // 1
Associating metadata
A
WeakMap
can be used to associate metadata with an object, without affecting the lifetime of the object itself. This is very similar to the private members example, since private members are also modelled as external metadata that doesn’t participate in prototypical inheritance.
This use case can be extended to already-created objects. For example, on the web, we may want to associate extra data with a DOM element, which the DOM element may access later. A common approach is to attach the data as a property:
const buttons = document.querySelectorAll(".button"); buttons.forEach((button) => { button.clicked = false; button.addEventListener("click", () => { button.clicked = true; const currentButtons = [...document.querySelectorAll(".button")]; if (currentButtons.every((button) => button.clicked)) { console.log("All buttons have been clicked!"); } }); });
This approach works, but it has a few pitfalls:
-
The
clicked
property is enumerable, so it will show up in
Object.keys(button)
,
for...in
loops, etc. This can be mitigated by using
Object.defineProperty()
, but that makes the code more verbose. -
The
clicked
property is a normal string property, so it can be accessed and overwritten by other code. This can be mitigated by using a
Symbol
key, but the key would still be accessible via
Object.getOwnPropertySymbols()
.
Using a
WeakMap
fixes these:
const buttons = document.querySelectorAll(".button"); const clicked = new WeakMap(); buttons.forEach((button) => { clicked.set(button, false); button.addEventListener("click", () => { clicked.set(button, true); const currentButtons = [...document.querySelectorAll(".button")]; if (currentButtons.every((button) => clicked.get(button))) { console.log("All buttons have been clicked!"); } }); });
Here, only code that has access to
clicked
knows the clicked state of each button, and external code can’t modify the states. In addition, if any of the buttons gets removed from the DOM, the associated metadata will automatically get garbage-collected.
Caching
You can associate objects passed to a function with the result of the function, so that if the same object is passed again, the cached result can be returned without re-executing the function. This is useful if the function is pure (i.e. it doesn’t mutate any outside objects or cause other observable side effects).
const cache = new WeakMap(); function handleObjectValues(obj) { if (cache.has(obj)) { return cache.get(obj); } const result = Object.values(obj).map(heavyComputation); cache.set(obj, result); return result; }
This only works if your function’s input is an object. Moreover, even if the input is never passed in again, the result still remains forever in the cache. A more effective way is to use a
Map
paired with
WeakRef
objects, which allows you to associate any type of input value with its respective (potentially large) computation result. See the WeakRefs and FinalizationRegistry example for more details.
Use case: caching
Another common example is caching. We can store (“cache”) results from a function, so that future calls on the same object can reuse it.
To achieve that, we can use
Map
(not optimal scenario):
// 📁 cache.js let cache = new Map(); // calculate and remember the result function process(obj) { if (!cache.has(obj)) { let result = /* calculations of the result for */ obj; cache.set(obj, result); return result; } return cache.get(obj); } // Now we use process() in another file: // 📁 main.js let obj = {/* let's say we have an object */}; let result1 = process(obj); // calculated // ...later, from another place of the code... let result2 = process(obj); // remembered result taken from cache // ...later, when the object is not needed any more: obj = null; alert(cache.size); // 1 (Ouch! The object is still in cache, taking memory!)
For multiple calls of
process(obj)
with the same object, it only calculates the result the first time, and then just takes it from
cache
. The downside is that we need to clean
cache
when the object is not needed any more.
If we replace
Map
with
WeakMap
, then this problem disappears. The cached result will be removed from memory automatically after the object gets garbage collected.
// 📁 cache.js let cache = new WeakMap(); // calculate and remember the result function process(obj) { if (!cache.has(obj)) { let result = /* calculate the result for */ obj; cache.set(obj, result); return result; } return cache.get(obj); } // 📁 main.js let obj = {/* some object */}; let result1 = process(obj); let result2 = process(obj); // ...later, when the object is not needed any more: obj = null; // Can't get cache.size, as it's a WeakMap, // but it's 0 or soon be 0 // When obj gets garbage collected, cached data will be removed as well
Tham khảo
- Javascript ES6 – Đôi điều thú vị có thể bạn chưa biết
- WeakMap – MDN Web Docs
- Difference between “Map” and “WeakMap” in JavaScript
Thank for your attention – Have a great day – Happy coding!
Bài viết gốc được đăng tải tại kieblog.vn
Có thể bạn quan tâm:
- Thiết kế Messaging Service WhatsApp – P2
- JavaScript Arrays và Objects thật ra không khác gì sách và báo
- Review source code – What make it better?
Xem thêm xin việc it hấp dẫn trên TopDev
The JavaScript ES6 has introduced two new data structures, i.e
Map
and
WeakMap
.
Map is similar to objects in JavaScript that allows us to store elements in a key/value pair.
The elements in a Map are inserted in an insertion order. However, unlike an object, a map can contain objects, functions and other data types as key.
WeakMap Methods
WeakMaps have methods
get()
,
set()
,
delete()
, and
has()
. For example,
const weakMap = new WeakMap(); console.log(weakMap); // WeakMap {} let obj = {}; // adding object (element) to WeakMap weakMap.set(obj, 'hello'); console.log(weakMap); // WeakMap {{} => "hello"} // get the element of a WeakMap console.log(weakMap.get(obj)); // hello // check if an element is present in WeakMap console.log(weakMap.has(obj)); // true // delete the element of WeakMap console.log(weakMap.delete(obj)); // true console.log(weakMap); // WeakMap {}
WeakSet
WeakSet
behaves similarly:
-
It is analogous to
Set
, but we may only add objects to
WeakSet
(not primitives). - An object exists in the set while it is reachable from somewhere else.
-
Like
Set
, it supports
add
,
has
and
delete
, but not
size
,
keys()
and no iterations.
Being “weak”, it also serves as additional storage. But not for arbitrary data, rather for “yes/no” facts. A membership in
WeakSet
may mean something about the object.
For instance, we can add users to
WeakSet
to keep track of those who visited our site:
let visitedSet = new WeakSet(); let john = { name: "John" }; let pete = { name: "Pete" }; let mary = { name: "Mary" }; visitedSet.add(john); // John visited us visitedSet.add(pete); // Then Pete visitedSet.add(john); // John again // visitedSet has 2 users now // check if John visited? alert(visitedSet.has(john)); // true // check if Mary visited? alert(visitedSet.has(mary)); // false john = null; // visitedSet will be cleaned automatically
The most notable limitation of
WeakMap
and
WeakSet
is the absence of iterations, and the inability to get all current content. That may appear inconvenient, but does not prevent
WeakMap/WeakSet
from doing their main job – be an “additional” storage of data for objects which are stored/managed at another place.
Javascript
|
Map1
Map(3) { 1 => 2, 2 => 3, 4 => 5 }
Map2
Map(3) {
‘firstname’ => ‘sumit’,
‘lastname’ => ‘ghosh’,
‘website’ => ‘geeksforgeeks’
}
Example 2: This example adds elements to the map using set() method.
Insert Item to Map
After you create a map, you can use the
set()
method to insert elements to it. For example,
// create a set let map1 = new Map(); // insert key-value pair map1.set('info', {name: 'Jack', age: 26}); console.log(map1); // Map {"info" => {name: "Jack", age: 26}}
You can also use objects or functions as keys. For example,
// Map with object key let map2 = new Map(); let obj = {}; map2.set(obj, {name: 'Jack', age: "26"}); console.log(map2); // Map {{} => {name: "Jack", age: "26"}}
Description
Keys of WeakMaps must be garbage-collectable. Most primitive data types can be arbitrarily created and don’t have a lifetime, so they cannot be used as keys. Objects and non-registered symbols can be used as keys because they are garbage-collectable.
Why WeakMap?
A map API could be implemented in JavaScript with two arrays (one for keys, one for values) shared by the four API methods. Setting elements on this map would involve pushing a key and value onto the end of each of those arrays simultaneously. As a result, the indices of the key and value would correspond to both arrays. Getting values from the map would involve iterating through all keys to find a match, then using the index of this match to retrieve the corresponding value from the array of values.
Such an implementation would have two main inconveniences:
-
The first one is an
O(n)
set and search (n being the number of keys in the map) since both operations must iterate through the list of keys to find a matching value. - The second inconvenience is a memory leak because the arrays ensure that references to each key and each value are maintained indefinitely. These references prevent the keys from being garbage collected, even if there are no other references to the object. This would also prevent the corresponding values from being garbage collected.
By contrast, in a
WeakMap
, a key object refers strongly to its contents as long as the key is not garbage collected, but weakly from then on. As such, a
WeakMap
:
- does not prevent garbage collection, which eventually removes references to the key object
-
allows garbage collection of any values if their key objects are not referenced from somewhere other than a
WeakMap
A
WeakMap
can be a particularly useful construct when mapping keys to information about the key that is valuable only if the key has not been garbage collected.
But because a
WeakMap
doesn’t allow observing the liveness of its keys, its keys are not enumerable. There is no method to obtain a list of the keys. If there were, the list would depend on the state of garbage collection, introducing non-determinism. If you want to have a list of keys, you should use a
Map
.
Iterate Over Map Keys
You can iterate over the Map and get the key using the
keys()
method. For example,
let map1 = new Map(); map1.set('name', 'Jack'); map1.set('age', '27'); // looping through the Map for (let key of map1.keys()) { console.log(key) }
Output
name age
new Map()
In this we use
new Map()
constructor,
Example: In this example, a Map named
prices
is created to associate product names with their respective prices, allowing for efficient retrieval and management of price information.
// Creating a Map for product pricesconst prices = new Map([ [“Laptop”, 1000], [“Smartphone”, 800], [“Tablet”, 400] ]);
Map.set():
You can add elements to a Map with the
set()
method.
Example: In this example, the
Map.set()
method is employed to add product prices to the Map named
prices
.
// Creating a Map for product prices const prices = new Map(); // Using Map.set() to add product prices prices.set(‘Laptop’, 1000); prices.set(‘Smartphone’, 800); // The Map now contains { ‘Laptop’ => 1000, ‘Smartphone’ => 800 }
Example 1: In this example, we will create a basic map object
Differences between Map and WeakMap
The functional mechanism of Map and WeakMap is same but they have little differences.
1) A WeakMap accepts only objects as keys whereas a Map,in addition to objects, accepts primitive datatype such as strings, numbers etc.
2) WeakMap objects doesn’t avert garbage collection if there are no references to the object which is acting like a key. Therefore there is no method to retrieve keys in WeakMap, whereas in Map there are methods such as Map.prototype.keys() to get the keys.
3) There is no size property exists in WeakMap.
JavaScript WeakMap
The WeakMap is similar to a Map. However, WeakMap can only contain objects as keys. For example,
const weakMap = new WeakMap(); console.log(weakMap); // WeakMap {} let obj = {}; // adding object (element) to WeakMap weakMap.set(obj, 'hello'); console.log(weakMap); // WeakMap {{} => "hello"}
When you try to add other data types besides objects, WeakMap throws an error. For example,
const weakMap = new WeakMap(); // adding string as a key to WeakMap weakMap.set('obj', 'hello');
// throws error // TypeError: Attempted to set a non-object key in a WeakMap
Use case: caching
Another common example is caching. We can store (“cache”) results from a function, so that future calls on the same object can reuse it.
To achieve that, we can use
Map
(not optimal scenario):
// 📁 cache.js let cache = new Map(); // calculate and remember the result function process(obj) { if (!cache.has(obj)) { let result = /* calculations of the result for */ obj; cache.set(obj, result); return result; } return cache.get(obj); } // Now we use process() in another file: // 📁 main.js let obj = {/* let's say we have an object */}; let result1 = process(obj); // calculated // ...later, from another place of the code... let result2 = process(obj); // remembered result taken from cache // ...later, when the object is not needed any more: obj = null; alert(cache.size); // 1 (Ouch! The object is still in cache, taking memory!)
For multiple calls of
process(obj)
with the same object, it only calculates the result the first time, and then just takes it from
cache
. The downside is that we need to clean
cache
when the object is not needed any more.
If we replace
Map
with
WeakMap
, then this problem disappears. The cached result will be removed from memory automatically after the object gets garbage collected.
// 📁 cache.js let cache = new WeakMap(); // calculate and remember the result function process(obj) { if (!cache.has(obj)) { let result = /* calculate the result for */ obj; cache.set(obj, result); return result; } return cache.get(obj); } // 📁 main.js let obj = {/* some object */}; let result1 = process(obj); let result2 = process(obj); // ...later, when the object is not needed any more: obj = null; // Can't get cache.size, as it's a WeakMap, // but it's 0 or soon be 0 // When obj gets garbage collected, cached data will be removed as well
Iterate Over Map Values
You can iterate over the Map and get the values using the
values()
method. For example,
let map1 = new Map(); map1.set('name', 'Jack'); map1.set('age', '27'); // looping through the Map for (let values of map1.values()) { console.log(values); }
Output
Jack 27
Javascript
|
Map(5) {
‘first name’ => ‘sumit’,
‘last name’ => ‘ghosh’,
‘website’ => ‘geeksforgeeks’,
‘friend 1’ => ‘gourav’,
‘friend 2’ => ‘sourav’
}
map1 has website ? true
map1 has friend 3 ? false
get…
Use case: additional data
The main area of application for
WeakMap
is an additional data storage.
If we’re working with an object that “belongs” to another code, maybe even a third-party library, and would like to store some data associated with it, that should only exist while the object is alive – then
WeakMap
is exactly what’s needed.
We put the data to a
WeakMap
, using the object as the key, and when the object is garbage collected, that data will automatically disappear as well.
weakMap.set(john, "secret documents"); // if john dies, secret documents will be destroyed automatically
Let’s look at an example.
For instance, we have code that keeps a visit count for users. The information is stored in a map: a user object is the key and the visit count is the value. When a user leaves (its object gets garbage collected), we don’t want to store their visit count anymore.
Here’s an example of a counting function with
Map
:
// 📁 visitsCount.js let visitsCountMap = new Map(); // map: user => visits count // increase the visits count function countUser(user) { let count = visitsCountMap.get(user) || 0; visitsCountMap.set(user, count + 1); }
And here’s another part of the code, maybe another file using it:
// 📁 main.js let john = { name: "John" }; countUser(john); // count his visits // later john leaves us john = null;
Now,
john
object should be garbage collected, but remains in memory, as it’s a key in
visitsCountMap
.
We need to clean
visitsCountMap
when we remove users, otherwise it will grow in memory indefinitely. Such cleaning can become a tedious task in complex architectures.
We can avoid it by switching to
WeakMap
instead:
// 📁 visitsCount.js let visitsCountMap = new WeakMap(); // weakmap: user => visits count // increase the visits count function countUser(user) { let count = visitsCountMap.get(user) || 0; visitsCountMap.set(user, count + 1); }
Now we don’t have to clean
visitsCountMap
. After
john
object becomes unreachable, by all means except as a key of
WeakMap
, it gets removed from memory, along with the information by that key from
WeakMap
.
In this article, we will talk about the difference between Map and WeakMap which are introduced by ES6. Javascript object supports only one key object. For supporting multiple key objects, Then Map comes on this path.
Map: A Map is an unordered list of key-value pairs where the key and the value can be of any type like string, boolean, number, etc. For better understanding, we take an example of Map and its properties.
Example: This example shows the implementation of Map in Javascript.
Javascript
|
Map(3) {
‘FirstName’ => ‘Shobhit’,
‘LastName’ => ‘Sharma’,
‘website’ => ‘GeeksforGeeks’
}
Example 3: This example explains the use of Map methods like has(), get(), delete(), and clear().
Sự khác biệt Map và Weak Map
2.1 Key Store
Cùng là cơ chế lưu trữ key-value. Nhưng có sự khác biệt rõ ràng về tiêu chuẩn của key.
A WeakMap accepts only objects as keys whereas a Map,in addition to objects, accepts primitive datatype such as strings, numbers etc.
WeakMap chỉ chấp nhận kiểu objects đóng vai trò như là key. Trong khi Map, ngoài kiểu Objects, nó còn chấp nhận cả các kiểu nguyên thủy như Strings, Numbers,…
map.set(44, 12); // Lỗi weakmap.set(44, 13); // Lỗi. Không thể tạo WeakMap từ 2D array. var map_1 = new WeakMap([[1, 2], [4, 5]]);
Mà cái thằng WeakMap này cũng dị. Mấy function hay methods dùng được với map thì không dùng được với Weakmap.
console.log(weakmap.size); //undefined //loop through the keys in an map for(var i of map) { console.log(i); } //loop through the keys in an weakmap doesn’t work for(var i of weakmap) { console.log(i); } //delete all keys map.clear(); weakmap.clear(); //but this works
Ngoài chuyện Primitive Type thì còn một vấn đề khác nữa là Memory Leak. Cái này là “cốt lõi”. Có nó mới có chữ Weak trong WeakMap. Khác biệt cốt lõi nhất!
2.2 Vấn đề Memory Leak
Memory thì từ xưa đến nay đã luôn là vấn đề cố hữu của Map. Một Map được tạo ra cũng đồng nghĩa với một phần memory được cấp phát. Cấp thì dễ, nhưng đôi khi mấy anh dev lại quên lấy lại phần đó (mặc dù đã sử dụng xong Map).
Sự khác biệt giữa Map và WeakMap lại là vấn đề này. Đây cũng là điểm khác biệt cần nắm rõ để có lựa chọn sáng suốt khi lựa chọn Map hay WeakMap.
Để dễ hiểu hơn thì ta có thể xem xét ví dụ sau:
JavaScript
var map = new Map(); var weakmap = new WeakMap(); (function(){ var a = {x: 12}; var b = {y: 12}; map.set(a, 1); weakmap.set(b, 2); })()
Xét như ví dụ phía trên, function tóm gọn lại từ dòng 4 đến dòng 10. Tuy nhiên để access được b = {y: 12}; bên ngoài function scope thực sự là không thể.
Mặc dù cả Map và Weakmap đều là global access variable. Tuy nhiên cơ chế của WeakMap cho phép Garbage collector xóa pointer tới b của chính nó. Bản thân chữa weak mang nghĩa là yếu, liên kết của weak map tới chính đứa con mà nó set vào là liên kết lỏng lẻo.
So “Map” can cause more garbages in memory. We can say that “Map” references are strong pointer whereas “WeakMap” references are weak pointers.
Chính vì vậy Map có thể chiếm dụng khá nhiều về mặt memory. Cũng có thể nói “map” tham chiếu mạnh hơn so với “WeakMap”. Tham chiếu ở đây được hiểu là tham chiếu tới memory được cấp phát.
Summary
WeakMap
is
Map
-like collection that allows only objects as keys and removes them together with associated value once they become inaccessible by other means.
WeakSet
is
Set
-like collection that stores only objects and removes them once they become inaccessible by other means.
Their main advantages are that they have weak reference to objects, so they can easily be removed by garbage collector.
That comes at the cost of not having support for
clear
,
size
,
keys
,
values
…
WeakMap
and
WeakSet
are used as “secondary” data structures in addition to the “primary” object storage. Once the object is removed from the primary storage, if it is only found as the key of
WeakMap
or in a
WeakSet
, it will be cleaned up automatically.
In this tutorial, we will learn about JavaScript WeakMap and WeakSet objects. WeakMap and WeakSet are two new data structures introduced to JavaScript in ES6. These data structures provide a way to store data in a memory-efficient way and are useful for working with large datasets. We will discuss their features, use cases, and how to use them in your code.
The WeakMap object is a collection of key/value pairs in which the keys are objects and the values can be arbitrary values. It is similar to Map, but it only allows objects as keys and the keys are held weakly. This means that if there is no other reference to the key object, the entry in the WeakMap can be garbage collected. WeakMap is a perfect fit for private properties in JavaScript.
WeakMap objects are collections of key/value pairs in which the keys are objects and the values can be arbitrary values. The key difference between WeakMap and Map is that the keys in WeakMap are held weakly. This means that if there is no other reference to the key object, the entry in the WeakMap can be garbage collected.
WeakMap objects have some advantages over Map objects. For example, they are not enumerable, so you can’t use the for…in loop to iterate over the values in a WeakMap. This makes them useful for storing private data, as they can’t be enumerated or accessed by other code.
WeakMap objects also have the advantage of being able to store weak references to objects. This means that if there is no other reference to the object, the entry in the WeakMap can be garbage collected. This makes WeakMap objects ideal for storing private data, as the data will be automatically cleaned up when there are no other references to it.
To create a WeakMap, you can use the new keyword. To add items to the WeakMap, you can use the set() method, which takes two arguments: the key and the value.
let weakMap = new WeakMap(); let key = {}; let value = 'value'; weakMap.set(key, value);
You can also use the get() method to retrieve the value associated with a given key.
let weakMap = new WeakMap(); let key = {}; let value = 'value'; weakMap.set(key, value); let retrievedValue = weakMap.get(key); console.log(retrievedValue); // 'value'
The main difference between WeakMap and Map is that the keys in WeakMap are held weakly. This means that if there is no other reference to the key object, the entry in the WeakMap can be garbage collected. This makes WeakMap objects ideal for storing private data, as the data will be automatically cleaned up when there are no other references to it.
Another difference between WeakMap and Map is that WeakMap objects are not enumerable. This means that you can’t use the for…in loop to iterate over the values in a WeakMap. This makes them useful for storing private data, as they can’t be enumerated or accessed by other code.
Finally, WeakMap objects are not iterable, so you can’t use the for…of loop to iterate over the values in a WeakMap. This makes them useful for storing private data, as they can’t be iterated or accessed by other code.
To learn more about weakmap, visit .
A WeakSet is a special type of collection that allows you to store weakly held objects. This means that the objects stored in a WeakSet can be garbage collected if there are no other references to them. WeakSets are useful for keeping track of objects that need to be removed from memory when they are no longer needed.
A WeakSet is similar to a Set, with the main difference being that it only stores objects, not primitive values. Also, unlike a Set, a WeakSet does not have a size property, and its entries cannot be iterated over. This makes WeakSets more memory-efficient than Sets.
WeakSets are useful for keeping track of objects that need to be removed from memory when they are no longer needed. For example, a WeakSet could be used to keep track of objects that have been marked as “garbage” and should be removed when no longer needed. WeakSets are also useful for keeping track of objects that are in a “temporary” state, such as objects that have been created for a short period of time and no longer need to be kept in memory.
To create a WeakSet, you can use the WeakSet constructor, which takes an iterable (an array or other iterable object) of objects as its argument. The WeakSet constructor will add each object in the iterable to the WeakSet.
let myWeakSet = new WeakSet([{a:1}, {b:2}, {c:3}]);
Once a WeakSet is created, you can add objects to it using the add() method. This method takes an object as its argument and adds it to the WeakSet.
let myWeakSet = new WeakSet([{a:1}, {b:2}, {c:3}]); let obj = {d:4}; myWeakSet.add(obj); console.log(myWeakSet);
You can also remove objects from a WeakSet using the delete() method. This method takes an object as its argument and removes it from the WeakSet.
let myWeakSet = new WeakSet([{a:1}, {b:2}, {c:3}]); let obj = {b:2}; myWeakSet.delete(obj); console.log(myWeakSet);
Finally, you can check if an object is in a WeakSet using the has() method. This method takes an object as its argument and returns true if the object is in the WeakSet, or false if it is not.
let myWeakSet = new WeakSet([{a:1}, {b:2}, {c:3}]); let obj = {b:2}; console.log(myWeakSet.has(obj));
To learn more about weakset, visit .
JavaScript map is a collection of elements where each element is stored as a Key, value pair. Map objects can hold both objects and primitive values as either key or value. When we iterate over the map object returns the key, and value pair in the same order as inserted. Map() constructor is used to create Map in JavaScript.
JavaScript Map has a property that represents the size of the map.
Example:
Input:let map1 = new Map([ [1 , 10], [2 , 20] , [3, 30],[4, 40] ]);console.log(“Map1: “);console.log(map1);Output:// Map1: // Map(4) { 1 => 10, 2 => 20, 3 => 30, 4 => 40 }
Instance properties
These properties are defined on
WeakMap.prototype
and shared by all
WeakMap
instances.
-
WeakMap.prototype.constructor
-
The constructor function that created the instance object. For
WeakMap
instances, the initial value is the
WeakMap
constructor. -
WeakMap.prototype[@@toStringTag]
-
The initial value of the
@@toStringTag
property is the string
"WeakMap"
. This property is used in
Object.prototype.toString()
.
WeakMap
In the below example we can find that WeakMap accepts only objects but not any primitive values (strings, numbers)
Example
Output
true fourth true
Kickstart Your Career
Get certified by completing the course
Get Started
Bài viết được sự cho phép của tác giả Kiên Nguyễn
Sự khác biệt map và weakmap luôn là một phần kiến thức cần nắm vững đối với lập trình viên Javascript. Nắm rõ sự khác biệt còn phải hiểu lúc nào nên sử dụng loại nào nữa. Đấy, vô vàn vấn đề cần tìm hiểu.
Tuy nhiên, khó cũng phải hiểu. Vì Data Structure không phải muốn dùng sao cũng được. Ở các System lớn, chỉ cần thay đổi một kiểu của DS thôi cũng gây ra hàng tá vấn đề.
Dữ liệu lớn, request xử lý hàng đống. Memory là thứ cần kiểm soát chặt chẽ để đảm bảo hệ thống luôn vận hành trơn tru. Kieblog hân hạnh giới thiệu bài viết sự khác biệt map và weakmap. Bắt đầu ngay thôi nào!
Tuyển dụng lập trình viên Javascript cho bạn
Get Key/Values of Map
You can iterate over the Map and get the key/value of a Map using the
entries()
method. For example,
let map1 = new Map(); map1.set('name', 'Jack'); map1.set('age', '27'); // looping through the Map for (let elem of map1.entries()) { console.log(`${elem[0]}: ${elem[1]}`); }
Output
name: Jack age: 27
Javascript
|
Output:
WeakMap {
}
WeakMap {
}
The element of a WeakMap – hello everyone
check if an element is present in WeakMap – true
deleting the element of WeakMap – true
WeakMap {
}
WeakMap {
}
ReferenceError: weakMap is not defined
Difference between Map and WeakMap:
Map |
WeakMap |
A Map is an unordered list of key-value pairs where the key and the value can be of any type like string, boolean, number, etc. | In a Weak Map, every key can only be an object and function. It used to store weak object references. |
Maps are iterable. | WeakMaps are not iterable. |
Maps will keep everything even if you don’t use them. | WeakMaps holds the reference to the key, not the key itself. |
The garbage collector doesn’t remove a key pointer from “Map” and also doesn’t remove the key from memory. | The garbage collector goes ahead and removes the key pointer from “WeakMap” and also removes the key from memory. WeakMap allows the garbage collector to do its task but not the Map. |
Maps have some properties : .set, .get, .delete, .size, .has, .forEach, Iterators. | WeakMaps have some properties : .set, .get, .delete, .has. |
You can create a new map by using a new Map(). | You can create a new WeakMap by using a new WeakMap(). |
Whether you’re preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape, GeeksforGeeks Courses are your key to success. We provide top-quality content at affordable prices, all geared towards accelerating your growth in a time-bound manner. Join the millions we’ve already empowered, and we’re here to do the same for you. Don’t miss out – check it out now!
Looking for a place to share your ideas, learn, and connect? Our Community portal is just the spot! Come join us and see what all the buzz is about!
Last Updated :
17 Apr, 2023
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment…
Đôi điều về Map, WeakMap trong Js
Bài đăng này đã không được cập nhật trong 5 năm
Trong lập trình thì bất kỳ ngôn ngữ nào bạn cũng phải trải qua xử lý các dữ liệu. Bài viết sẽ giới thiệu về Map và WeakMap kèm ứng dụng của chúng để có thể giúp bạn hiểu và có thể đâu đó áp dụng vào code của bạn để giải quyết vấn đề trơn tru hơn. Map: 1 key đi với 1 value Với Js thì bạn có thể thể hiện cấu trúc này qua object
const dict = { company: 'Framgia', Title: 'We made it awesome', } console.log(dict['company']) // Framgia
Với việc dùng object thì có thể chuỗi lấy dùng làm khóa
const obj = { foobar: 2 } const dict = new Map() dict .set('foo', 123) .set(obj, 'hello framgia') dict.get('foo') // 123 dict.get(obj) // 'hello framgia' // get value một khóa không tồn tại dict.get('bar') // undefined
Ở đây chúng ta có thể truyền vào constructor của Map một array với cặp value dạng [key, value]:
const dict = new Map([ ['foo', 123], [obj, 'hello framgia'] ])
Chúng ta có thể dùng bất kỳ kiểu dữ liệu để làm khóa cho Map (array, object, funtion or NaN).
const arr = [1] const f = () => {} dict .set(arr, 'array') .set(f, 'function') .set(NaN, 'not a number')
Để tìm key và value tương ứng trong Map ta dùng SameValueZero. SameValueZero mang ý nghĩa giống với === nhưng xem value của NaN là bằng nhau. SameValueZero sẽ nhận biết 2 object khác nhau sẽ là hai khóa riêng biệt
const bar = {} const foo = {} dict.set(bar, 'bar').set(foo, 'foo') dict.get(foo) // foo dict.get({}) // undefined
Khi map đã tồn tại key thì dữ liệu mới sẽ ghi đè lên.
const cst = new Map() cst.set('bar', 1000001) cst.set('bar', 1000002) cst.get('bar') // 1000002
Vậy làm thế nào để duyệt qua Map? Chúng ta sẽ dùng:
const dict = new Map([ ['key1', 96], ['key2', 69] ]) dict.keys() // ['key1', 'key2'] dict.values() // [96, 69] dict.entries() // [ ['key1', 96], ['key2', 69] ] dict.forEach(function(value, key, map) { console.log(`${key} has ${value}`) }, /* thisArgs bạn có thể truyền vào tham chiếu cho `this`/) // Sử dụng for..of for (let [key, value] of dict) { console.log(`${key} has ${value}`) }
Thao tác khác với Map:
const dict = new Map([ ['key1', 121], ['key', 212] ]) // Đếm số cặp giá trị trong map dict.size // 2 // Kiểm tra trong map có khóa "foo" hay không dict.has('key1') // true dict.has('foo') // false // Xóa một khóa, trả về true nếu thành công, false nếu thất bại dict.delete('foo') // false dict.delete('key2') // true // Xóa hết các cặp giá trị của map dict.clear()
WeakMap: có phương thức tương tự như Map, chỉ khác ở chổ bạn không thể duyệt WeakMap bằng phương thức .key() và .values(), .entries() và for..of với một lý do rất được quan tâm đó là “bảo toàn dữ liệu”. với WeakMap thì dữ liệu sẽ là private tức là bảo mật nhưng lại không gây rò rỉ bộ nhớ.
const weakMap = new WeakMap() class User { constructor() { const data = { cellPhone: 0905999999 } weakMap.set(this, data) } getCellPhone() { const data = privates.get(this) return data.cellPhone } } const user = new User() console.log(user) // {} console.log(user.getCellPhone()) // 0905999999
Map có những cải tiến hơn so với object, Map là công cụ hữu hiệu giúp lưu trữ dự liệu theo dạng (key, value). Tham khảo: 1 WeakMap for JavaScript Private Data – Steve Brownlee
All rights reserved
WeakMap
A
WeakMap
is a collection of key/value pairs whose keys must be objects or non-registered symbols, with values of any arbitrary JavaScript type, and which does not create strong references to its keys. That is, an object’s presence as a key in a
WeakMap
does not prevent the object from being garbage collected. Once an object used as a key has been collected, its corresponding values in any
WeakMap
become candidates for garbage collection as well — as long as they aren’t strongly referred to elsewhere. The only primitive type that can be used as a
WeakMap
key is symbol — more specifically, non-registered symbols — because non-registered symbols are guaranteed to be unique and cannot be re-created.
WeakMap
allows associating data to objects in a way that doesn’t prevent the key objects from being collected, even if the values reference the keys. However, a
WeakMap
doesn’t allow observing the liveness of its keys, which is why it doesn’t allow enumeration; if a
WeakMap
exposed any method to obtain a list of its keys, the list would depend on the state of garbage collection, introducing non-determinism. If you want to have a list of keys, you should use a
Map
rather than a
WeakMap
.
You can learn more about
WeakMap
in the WeakMap object section of the Keyed collections guide.
See also
-
Polyfill of
WeakMap
in
core-js
- Keyed collections
- Hiding Implementation Details with ECMAScript 6 WeakMaps by Nick Fitzgerald (2014)
-
Map
-
Set
-
WeakSet
As we know from the chapter Garbage collection, JavaScript engine keeps a value in memory while it is “reachable” and can potentially be used.
For instance:
let john = { name: "John" }; // the object can be accessed, john is the reference to it // overwrite the reference john = null; // the object will be removed from memory
Usually, properties of an object or elements of an array or another data structure are considered reachable and kept in memory while that data structure is in memory.
For instance, if we put an object into an array, then while the array is alive, the object will be alive as well, even if there are no other references to it.
Like this:
let john = { name: "John" }; let array = [ john ]; john = null; // overwrite the reference // the object previously referenced by john is stored inside the array // therefore it won't be garbage-collected // we can get it as array[0]
Similar to that, if we use an object as the key in a regular
Map
, then while the
Map
exists, that object exists as well. It occupies memory and may not be garbage collected.
For instance:
let john = { name: "John" }; let map = new Map(); map.set(john, "..."); john = null; // overwrite the reference // john is stored inside the map, // we can get it by using map.keys()
WeakMap
is fundamentally different in this aspect. It doesn’t prevent garbage-collection of key objects.
Let’s see what it means on examples.
WeakSet
WeakSet
behaves similarly:
-
It is analogous to
Set
, but we may only add objects to
WeakSet
(not primitives). - An object exists in the set while it is reachable from somewhere else.
-
Like
Set
, it supports
add
,
has
and
delete
, but not
size
,
keys()
and no iterations.
Being “weak”, it also serves as additional storage. But not for arbitrary data, rather for “yes/no” facts. A membership in
WeakSet
may mean something about the object.
For instance, we can add users to
WeakSet
to keep track of those who visited our site:
let visitedSet = new WeakSet(); let john = { name: "John" }; let pete = { name: "Pete" }; let mary = { name: "Mary" }; visitedSet.add(john); // John visited us visitedSet.add(pete); // Then Pete visitedSet.add(john); // John again // visitedSet has 2 users now // check if John visited? alert(visitedSet.has(john)); // true // check if Mary visited? alert(visitedSet.has(mary)); // false john = null; // visitedSet will be cleaned automatically
The most notable limitation of
WeakMap
and
WeakSet
is the absence of iterations, and the inability to get all current content. That may appear inconvenient, but does not prevent
WeakMap/WeakSet
from doing their main job – be an “additional” storage of data for objects which are stored/managed at another place.
Use case: additional data
The main area of application for
WeakMap
is an additional data storage.
If we’re working with an object that “belongs” to another code, maybe even a third-party library, and would like to store some data associated with it, that should only exist while the object is alive – then
WeakMap
is exactly what’s needed.
We put the data to a
WeakMap
, using the object as the key, and when the object is garbage collected, that data will automatically disappear as well.
weakMap.set(john, "secret documents"); // if john dies, secret documents will be destroyed automatically
Let’s look at an example.
For instance, we have code that keeps a visit count for users. The information is stored in a map: a user object is the key and the visit count is the value. When a user leaves (its object gets garbage collected), we don’t want to store their visit count anymore.
Here’s an example of a counting function with
Map
:
// 📁 visitsCount.js let visitsCountMap = new Map(); // map: user => visits count // increase the visits count function countUser(user) { let count = visitsCountMap.get(user) || 0; visitsCountMap.set(user, count + 1); }
And here’s another part of the code, maybe another file using it:
// 📁 main.js let john = { name: "John" }; countUser(john); // count his visits // later john leaves us john = null;
Now,
john
object should be garbage collected, but remains in memory, as it’s a key in
visitsCountMap
.
We need to clean
visitsCountMap
when we remove users, otherwise it will grow in memory indefinitely. Such cleaning can become a tedious task in complex architectures.
We can avoid it by switching to
WeakMap
instead:
// 📁 visitsCount.js let visitsCountMap = new WeakMap(); // weakmap: user => visits count // increase the visits count function countUser(user) { let count = visitsCountMap.get(user) || 0; visitsCountMap.set(user, count + 1); }
Now we don’t have to clean
visitsCountMap
. After
john
object becomes unreachable, by all means except as a key of
WeakMap
, it gets removed from memory, along with the information by that key from
WeakMap
.
WeakMap
The first difference between
Map
and
WeakMap
is that keys must be objects, not primitive values:
Now, if we use an object as the key in it, and there are no other references to that object – it will be removed from memory (and from the map) automatically.
let john = { name: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); john = null; // overwrite the reference // john is removed from memory!
Compare it with the regular
Map
example above. Now if
john
only exists as the key of
WeakMap
– it will be automatically deleted from the map (and memory).
WeakMap
does not support iteration and methods
keys()
,
values()
,
entries()
, so there’s no way to get all keys or values from it.
WeakMap
has only the following methods:
Why such a limitation? That’s for technical reasons. If an object has lost all other references (like
john
in the code above), then it is to be garbage-collected automatically. But technically it’s not exactly specified when the cleanup happens.
The JavaScript engine decides that. It may choose to perform the memory cleanup immediately or to wait and do the cleaning later when more deletions happen. So, technically, the current element count of a
WeakMap
is not known. The engine may have cleaned it up or not, or did it partially. For that reason, methods that access all keys/values are not supported.
Now, where do we need such a data structure?
Iterate Through a Map
You can iterate through the Map elements using the for…of loop or forEach() method. The elements are accessed in the insertion order. For example,
let map1 = new Map(); map1.set('name', 'Jack'); map1.set('age', '27'); // looping through Map for (let [key, value] of map1) { console.log(key + '- ' + value); }
Output
name- Jack age- 27
You could also get the same results as the above program using the
forEach()
method. For example,
// using forEach method() let map1 = new Map(); map1.set('name', 'Jack'); map1.set('age', '27'); // looping through Map map1.forEach(function(value, key) { console.log(key + '- ' + value) })
Instance methods
-
WeakMap.prototype.delete()
-
Removes any value associated to the
key
.
WeakMap.prototype.has(key)
will return
false
afterwards. -
WeakMap.prototype.get()
-
Returns the value associated to the
key
, or
undefined
if there is none. -
WeakMap.prototype.has()
-
Returns a Boolean asserting whether a value has been associated to the
key
in the
WeakMap
object or not. -
WeakMap.prototype.set()
-
Sets the
value
for the
key
in the
WeakMap
object. Returns the
WeakMap
object.
WeakMaps Are Not iterable
Unlike Maps, WeakMaps are not iterable. For example,
const weakMap = new WeakMap(); console.log(weakMap); // WeakMap {} let obj = {}; // adding object (element) to WeakMap weakMap.set(obj, 'hello'); // looping through WeakMap for (let i of weakMap) { console.log(i); // TypeError }
JavaScript
Map
and
WeakMap
were introduced in ES6. Some browsers may not support their use. To learn more, visit JavaScript Map support and JavaScript WeakMap support.
As we know from the chapter Garbage collection, JavaScript engine keeps a value in memory while it is “reachable” and can potentially be used.
For instance:
let john = { name: "John" }; // the object can be accessed, john is the reference to it // overwrite the reference john = null; // the object will be removed from memory
Usually, properties of an object or elements of an array or another data structure are considered reachable and kept in memory while that data structure is in memory.
For instance, if we put an object into an array, then while the array is alive, the object will be alive as well, even if there are no other references to it.
Like this:
let john = { name: "John" }; let array = [ john ]; john = null; // overwrite the reference // the object previously referenced by john is stored inside the array // therefore it won't be garbage-collected // we can get it as array[0]
Similar to that, if we use an object as the key in a regular
Map
, then while the
Map
exists, that object exists as well. It occupies memory and may not be garbage collected.
For instance:
let john = { name: "John" }; let map = new Map(); map.set(john, "..."); john = null; // overwrite the reference // john is stored inside the map, // we can get it by using map.keys()
WeakMap
is fundamentally different in this aspect. It doesn’t prevent garbage-collection of key objects.
Let’s see what it means on examples.
Supported Browsers:
- Chrome
- Edge
- Firefox
- Opera
- Safari
- Internet Explorer
We have a complete list of Javascript Map methods, to check them please go through the Javascript Map Reference article.
Whether you’re preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape, GeeksforGeeks Courses are your key to success. We provide top-quality content at affordable prices, all geared towards accelerating your growth in a time-bound manner. Join the millions we’ve already empowered, and we’re here to do the same for you. Don’t miss out – check it out now!
Looking for a place to share your ideas, learn, and connect? Our Community portal is just the spot! Come join us and see what all the buzz is about!
Last Updated :
16 Jan, 2024
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment…
Looking this and this MDN pages it seems like the only difference between Maps and WeakMaps is a missing “size” property for WeakMaps. But is this true? What’s the difference between them?
- The effect is on the GC. WeakMaps can have their keys collected. Mar 24, 2013 at 21:35
- @JanDvorak there’s no example pointed on MDN about it. Like aWeakMap.get(key); // say, 2 …(GC action)… aWeakMap.get(key); // say, undefined Mar 25, 2013 at 4:34
-
1Your example is impossible.
key
cannot be collected, because it’s referenced by you. Mar 25, 2013 at 4:43 - 1The design decision is that GC actions are invisible in Javascript. You can’t observe GC doing its thing. Mar 25, 2013 at 5:58
- 1See this related answer for more information about this problem. Aug 16, 2015 at 17:22
JavaScript Map vs Object
Map | Object |
Maps can contain objects and other data types as keys. | Objects can only contain strings and symbols as keys. |
Maps can be directly iterated and their value can be accessed. | Objects can be iterated by accessing its keys. |
The number of elements of a Map can be determined by | The number of elements of an object needs to be determined manually. |
Map performs better for programs that require the addition or removal of elements frequently. | Object does not perform well if the program requires the addition or removal of elements frequently. |
Keywords searched by users: map and weakmap in javascript
Categories: Sưu tầm 36 Map And Weakmap In Javascript
See more here: kientrucannam.vn
See more: https://kientrucannam.vn/vn/