Es6 Collection Map, Set, WeakMap, WeakSet

Es6 Collection Map, Set, WeakMap, WeakSet

Objects and arrays were the workhorses of JavaScript. ES6 introduces four new data structures that will add power and expressiveness to the language: `Map`, `Set`, `WeakSet`, and `WeakMap`.

Most major programming languages have several types of data collections. Python has lists, tuples, and dictionaries. Java has lists, sets, maps, queues. Ruby has hashes and arrays. JavaScript, up until now, had only arrays. Objects and arrays were the workhorses of JavaScript. ES6 introduces four new data structures that will add power and expressiveness to the language: Map, Set, WeakSet, and WeakMap.

Searching for the JavaScript HashMap

HashMaps, dictionaries, and hashes are several ways that various programming languages store key/value pairs, and these data structures are optimized for fast retrieval.

In ES5, JavaScript objects — which are just arbitrary collections of properties with keys and values — can simulate hashes, but there are several downsides to using objects as hashes.

Downside #1: Keys must be strings in ES5

JavaScript object property keys must be strings, which limits their ability to serve as a collection of key/value pairs of varying data types. You can, of course, coerce/stringify other data types into strings, but this adds extra work.

Downside #2: Objects are not inherently iterable

Objects weren’t designed to be used as collections, and as a result there’s no efficient way to determine how many properties an object has. (See, for example, Object.keys is slow). When you loop over an object’s properties, you also get its prototype properties. You could add the iterable property to all objects, but not all objects are meant to be used as collections. You could use the for … in loop and the hasOwnProperty() method, but this is just a workaround. When you loop over an object’s properties, the properties won’t necessarily be retrieved in the same order they were inserted.

Downside #3: Challenges with built-in method collisions

Objects have built-in methods like constructor, toString, and valueOf. If one of these was added as a property, it could cause collisions. You could use Object.create(null) to create a bare object (which doesn’t inherit from object.prototype), but, again, this is just a workaround.

ES6 includes new collection data types, so there’s no longer a need to use objects and live with their drawbacks.

Using ES6 Map Collections

Map is the first data structure/collection we’ll examine. Maps are collections of keys and values of any type. It’s easy to create new Maps, add/remove values, loop over keys/values and efficiently determine their size. Here are the crucial methods:

Creating a map and using common methods

const map = new Map(); // Create a new Map
map.set('hobby', 'cycling'); // Sets a key value pair

const foods = { dinner: 'Curry', lunch: 'Sandwich', breakfast: 'Eggs' }; // New Object
const normalfoods = {}; // New Object

map.set(normalfoods, foods); // Sets two objects as key value pair

for (const [key, value] of map) {
  console.log(`${key} = ${value}`); // hobby = cycling  [object Object] = [object Object]
}

map.forEach((value, key) => {
  console.log(`${key} = ${value}`);
}, map); // hobby = cycling  [object Object] = [object Object]

map.clear(); // Clears key value pairs
console.log(map.size === 0); // True

Run this example on JSBin

Using the Set Collection

Sets are ordered lists of values that contain no duplicates. Instead of being indexed like arrays are, sets are accessed using keys. Sets already exist in Java, Ruby, Python, and many other languages. One difference between ES6 Sets and those in other languages is that the order matters in ES6 (not so in many other languages). Here are the crucial Set methods:

const planetsOrderFromSun = new Set();
planetsOrderFromSun.add('Mercury');
planetsOrderFromSun.add('Venus').add('Earth').add('Mars'); // Chainable Method
console.log(planetsOrderFromSun.has('Earth')); // True

planetsOrderFromSun.delete('Mars');
console.log(planetsOrderFromSun.has('Mars')); // False

for (const x of planetsOrderFromSun) {
  console.log(x); // Same order in as out - Mercury Venus Earth
}
console.log(planetsOrderFromSun.size); // 3

planetsOrderFromSun.add('Venus'); // Trying to add a duplicate
console.log(planetsOrderFromSun.size); // Still 3, Did not add the duplicate

planetsOrderFromSun.clear();
console.log(planetsOrderFromSun.size); // 0

Run this example on JSBin

Weak Collections, Memory, and Garbage Collections

JavaScript Garbage Collection is a form of memory management whereby objects that are no longer referenced are automatically deleted and their resources are reclaimed.

Map and Set‘s references to objects are strongly held and will not allow for garbage collection. This can get expensive if maps/sets reference large objects that are no longer needed, such as DOM elements that have already been removed from the DOM.

To remedy this, ES6 also introduces two new weak collections called WeakMap and WeakSet. These ES6 collections are ‘weak’ because they allow for objects which are no longer needed to be cleared from memory.

WeakMap

WeakMap is the third of the new ES6 collections we’re covering. WeakMaps are similar to normal Maps, albeit with fewer methods and the aforementioned difference with regards to garbage collection.

const aboutAuthor = new WeakMap(); // Create New WeakMap
const currentAge = {}; // key must be an object
const currentCity = {}; // keys must be an object

aboutAuthor.set(currentAge, 30); // Set Key Values
aboutAuthor.set(currentCity, 'Denver'); // Key Values can be of different data types

console.log(aboutAuthor.has(currentCity)); // Test if WeakMap has a key

aboutAuthor.delete(currentAge); // Delete a key

Run this example on JSBin

Use cases

WeakMaps have several popular use cases. They can be used to keep an object’s private data private, and they can also be used to keep track of DOM nodes/objects.

Private data use case

The following example is from JavaScript expert Nicholas C. Zakas:

var Person = (function() {
  var privateData = new WeakMap();

  function Person(name) {
    privateData.set(this, { name: name });
  }

  Person.prototype.getName = function() {
    return privateData.get(this).name;
  };

  return Person;
}());

Using a WeakMap here simplifies the process of keeping an object’s data private. It’s possible to reference the Person object, but access to the privateDataWeakMap is disallowed without the specific Person instance.

DOM nodes use case

The Google Polymer project uses WeakMaps in a piece of code called PositionWalker.

PositionWalker keeps track of a position within a DOM subtree, as a current node and an offset within that node.

WeakMap is used to keep track of DOM node edits, removals, and changes:

_makeClone() {
  this._containerClone = this.container.cloneNode(true);
  this._cloneToNodes = new WeakMap();
  this._nodesToClones = new WeakMap();

  ...

  let n = this.container;
  let c = this._containerClone;

  // find the currentNode's clone
  while (n !== null) {
    if (n === this.currentNode) {
    this._currentNodeClone = c;
    }
    this._cloneToNodes.set(c, n);
    this._nodesToClones.set(n, c);

    n = iterator.nextNode();
    c = cloneIterator.nextNode();
  }
}

WeakSet

WeakSets are Set Collections whose elements can be garbage collected when objects they’re referencing are no longer needed. WeakSets don’t allow for iteration. Their use cases are rather limited (for now, at least). Most early adopters say that WeakSets can be used to tag objects without mutating them. ES6-Features.org has an example of adding and deleting elements from a WeakSet in order to keep track of whether or not the objects have been marked:

let isMarked     = new WeakSet()
let attachedData = new WeakMap()

export class Node {
    constructor (id)   { this.id = id                  }
    mark        ()     { isMarked.add(this)            }
    unmark      ()     { isMarked.delete(this)         }
    marked      ()     { return isMarked.has(this)     }
    set data    (data) { attachedData.set(this, data)  }
    get data    ()     { return attachedData.get(this) }
}

let foo = new Node("foo")

JSON.stringify(foo) === '{"id":"foo"}'
foo.mark()
foo.data = "bar"
foo.data === "bar"
JSON.stringify(foo) === '{"id":"foo"}'

isMarked.has(foo)     === true
attachedData.has(foo) === true
foo = null  /* remove only reference to foo */
attachedData.has(foo) === false
isMarked.has(foo)     === false

Map All Things? Records vs ES6 Collections

Maps and Sets are nifty new ES6 collections of key/value pairs. That said, JavaScript objects still can be used as collections in many situations. No need to switch to the new ES6 collections unless the situation calls for it.

MDN has has a nice list of questions to determine when to use an object or a keyed collection:

  • Are keys usually unknown until run time, and do you need to look them up dynamically?
  • Do all values have the same type, and can be used interchangeably?
  • Do you need keys that aren’t strings?
  • Are key-value pairs often added or removed?
  • Do you have an arbitrary (easily changing) amount of key-value pairs?
  • Is the collection iterated?
New ES6 Collections Yield a More Usable JavaScript

JavaScript collections have previously been quite limited, but this has been remedied with ES6. These new ES6 collections will add power and flexibility to the language, as well as simplify the task of JavaScript developers who adopt them.

Programming a Javascript Simon Game Tutorial

Programming a Javascript Simon Game Tutorial

In this javascript tutorial, I recorded myself live programming an html5 javascript simon game.

In this javascript tutorial, I recorded myself live programming an html5 javascript simon game.

For those who don't know, I'm a full stack web developer who has been in the industry for over 5 years now. There is a lot of things I have learned along the way and I'd like to share that knowledge with anyone wanting to learn!

like this video if you found it useful and would like to see more videos of the same content.

subscribe to my channel if you are trying to improve your abilities as a web developer, software engineer, or even if you are just learning to code.

Don't forget to turn on those bell notifications!

Understanding Memoization And Dynamic Programming in Javascript

Understanding Memoization And Dynamic Programming in Javascript

In this Javascript tutorial I will explain what memoization is, how to use it, when you should use memoization, how to use memoization, what dynamic programming is, how to use memoization in dynamic programming. Memoization is a big complicated word that you may have never even heard before, but you may be surprised to know that you are most likely already using memoization without even realizing it.

Memoization is a big complicated word that you may have never even heard before, but you may be surprised to know that you are most likely already using memoization without even realizing it. Memoization is just the act of caching values so that they can be calculated quicker in the future. Memoization is really useful in all parts of programming, but where it is most useful is in dynamic programming. In this video I will explain what memoization is, how to use it, and why it is so useful especially in dynamic programming.

🧠 Concepts Covered:

  • What memoization is
  • When you should use memoization
  • How to use memoization
  • What dynamic programming is
  • How to use memoization in dynamic programming

JavaScript Tutorial: if-else Statement in JavaScript

JavaScript Tutorial: if-else Statement in JavaScript

This JavaScript tutorial is a step by step guide on JavaScript If Else Statements. Learn how to use If Else in javascript and also JavaScript If Else Statements. if-else Statement in JavaScript. JavaScript's conditional statements: if; if-else; nested-if; if-else-if. These statements allow you to control the flow of your program's execution based upon conditions known only during run time.

Decision Making in programming is similar to decision making in real life. In programming also we face some situations where we want a certain block of code to be executed when some condition is fulfilled.
A programming language uses control statements to control the flow of execution of the program based on certain conditions. These are used to cause the flow of execution to advance and branch based on changes to the state of a program.

JavaScript’s conditional statements:

  • if
  • if-else
  • nested-if
  • if-else-if

These statements allow you to control the flow of your program’s execution based upon conditions known only during run time.

  • if: if statement is the most simple decision making statement. It is used to decide whether a certain statement or block of statements will be executed or not i.e if a certain condition is true then a block of statement is executed otherwise not.
    Syntax:
if(condition) 
{
   // Statements to execute if
   // condition is true
}

Here, condition after evaluation will be either true or false. if statement accepts boolean values – if the value is true then it will execute the block of statements under it.
If we do not provide the curly braces ‘{‘ and ‘}’ after if( condition ) then by default if statement will consider the immediate one statement to be inside its block. For example,

if(condition)
   statement1;
   statement2;

// Here if the condition is true, if block 
// will consider only statement1 to be inside 
// its block.

Flow chart:

Example:

<script type = "text/javaScript"> 

// JavaScript program to illustrate If statement 

var i = 10; 

if (i > 15) 
document.write("10 is less than 15"); 

// This statement will be executed 
// as if considers one statement by default 
document.write("I am Not in if"); 

< /script> 

Output:

I am Not in if
  • if-else: The if statement alone tells us that if a condition is true it will execute a block of statements and if the condition is false it won’t. But what if we want to do something else if the condition is false. Here comes the else statement. We can use the else statement with if statement to execute a block of code when the condition is false.
    Syntax:
if (condition)
{
    // Executes this block if
    // condition is true
}
else
{
    // Executes this block if
    // condition is false
}


Example:

<script type = "text/javaScript"> 

// JavaScript program to illustrate If-else statement 

var i = 10; 

if (i < 15) 
document.write("10 is less than 15"); 
else
document.write("I am Not in if"); 

< /script> 

Output:

i is smaller than 15
  • nested-if A nested if is an if statement that is the target of another if or else. Nested if statements means an if statement inside an if statement. Yes, JavaScript allows us to nest if statements within if statements. i.e, we can place an if statement inside another if statement.
    Syntax:
if (condition1) 
{
   // Executes when condition1 is true
   if (condition2) 
   {
      // Executes when condition2 is true
   }
}

Example:

<script type = "text/javaScript"> 

// JavaScript program to illustrate nested-if statement 

var i = 10; 

if (i == 10) { 

// First if statement 
if (i < 15) 
	document.write("i is smaller than 15"); 

// Nested - if statement 
// Will only be executed if statement above 
// it is true 
if (i < 12) 
	document.write("i is smaller than 12 too"); 
else
	document.write("i is greater than 15"); 
} 
< /script> 

Output:

i is smaller than 15
i is smaller than 12 too
  • if-else-if ladder Here, a user can decide among multiple options.The if statements are executed from the top down. As soon as one of the conditions controlling the if is true, the statement associated with that if is executed, and the rest of the ladder is bypassed. If none of the conditions is true, then the final else statement will be executed.
if (condition)
    statement;
else if (condition)
    statement;
.
.
else
    statement;


Example:

<script type = "text/javaScript"> 
// JavaScript program to illustrate nested-if statement 

var i = 20; 

if (i == 10) 
document.wrte("i is 10"); 
else if (i == 15) 
document.wrte("i is 15"); 
else if (i == 20) 
document.wrte("i is 20"); 
else
document.wrte("i is not present"); 
< /script> 

Output:

i is 20