Fat Arrow Functions

They provide syntactical sugar and make the this keyword resolve lexically.

const a = () => '5'
const b = num => num+1;

Above fat arrow examples show a.) implicit return and b.) no need of paranthesis when there is only a single parameter to be passed

class Foo {
  constructor(name) {
    this.name = name;
  }
  
  speak(){
    console.log(`I am ${this.name}`); 
  }
}
var f = new Foo('sandeep');
f.speak(); // I am sandeep
let abc = f.speak;
abc(); //  Cannot read property 'name' of undefined

Above happens because in this context this is undefined.

To read more about Fat Array Functions go here: http://sandeep45.github.io/javascript/es6/functions/2016/02/08/fat-arrow-functions.html

Function Arguments

Default values can be assigned in the function declaration. Its basically checking if the values are undefined, and if that is the case it uses the value you passed in.

const printName = (name = 'Sandeep') => console.log(`I am ${name}`)
printName('Foo') // I am Foo
printName() // I am Sandeep
printName(undefined) // I am Sandeep
printName(void(0)) // I am Sandeep

Arguments can be deconstructed right in the function declaration. By adding three dots ... before the name of the variable, we have made it an array which will catch all remaining parameters

const names = (mother, father, ...restOfFamily) => {
  console.log(mother, father);
  console.log(restOfFamily);
  console.log(restOfFamily.length);
}
names("foo", "moo", "bar", "jones", "adam");
// foo, moo
// [bar, jones, "adam"]
// 3

A similar deconstructing can also be done when the argument is an object/Hash. By specifying keys of the hash we want, we can put them in a variable, and then optionally put the rest in a object/hash variable.

const names = ({mother, father, ...restOfFamily}) => {
  console.log(mother, father);
  console.log(restOfFamily);
  console.log(restOfFamily.length);
};
names({
  mother: 'foo',
  father: 'moo',
  brother: 'bar',
  sister: 'jones',
  uncle: 'adam'
});
// foo, moo
// {brother: 'bar', sister: 'jones', uncle: 'adam'}
// 3

We can also __deconstruct` similarly when the argument is an array. We can just specify variables at indexes we want and optionally put the rest in an array variable.

const names = ([mother, father, ...restOfFamily]) => {
  console.log(mother, father);
  console.log(restOfFamily);
  console.log(restOfFamily.length);
};
names([
  'foo',
  'moo',
  'bar',
  'jones',
  'adam'
]);
// foo, moo
// 'bar', 'jones','adam'}
// 3

You can also mix deconstructing of an object along with default values:

const a = ({x=100,y=200}) => {
  console.log(x,y)
}

a({
  x: 1,
  z: 2,
});

// 1 200

Deconstructing

Selectively take what you want from an object by key and from an array by index.

var {name}  = {name: 'Sandeep', age: 34}
console.log(name); // Sandeep

var {name:myFirstName}  = {name: 'Sandeep', age: 34}
console.log(myFirstName); // Sandeep

var [name] = {Sandeep, 34}
console.log(name); // Sandeep

var [name,,id] = {Sandeep, 34, a1234}
console.log(name); // Sandeep
console.log(id); // a12345

You can read more on deconstructing here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters

For-Of Loop

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for…of

The for-of loop is use it to iterate over an objects iterable items in random order. This is different from a for-in loop which is used to iterate over an objects enumerable properties in their insertion/creation order.

const items = [1, 5, 10];
for(let i of items) { 
  console.log(i); // prints 1, then 5 and then 10
}
console.log(i); // i not defined as we used let vs var

This works like shown above, because the Array object has an iterator function defined which is returning the items of the array as iterable items. String, Map etc. also have their own version of iterator functions.

Array.prototype.mynameis = 'sandeep';
let items = [1, 5, 10];
for(let i in items) { 
  console.log(i); // 0, 1, 2, mynameis 
}
for(let i in items) { 
  console.log(items[i]); // 1, 5, 10, 'sandeep' 
}

Now yes, we could use hasOwnProperty to check and ignore properties which dont belong to items and then lookup the values of those properties on items, to get the same answer, but that misses the point here, which is that for-of iterates over iteratable items which one may even customly defined by defining the iterator generator function.

 Array.prototype.mynameis = 'sandeep';
 let items = [1, 5, 10];
 for(let i in items) {
   if( items.hasOwnProperty(i) ) {
      console.log(items[i]); // 1, 5, 10
   }  
 }

let, const & var

Use let to have a variable scoped to the block instead of the function, which is what var does.

Since let is scoped to the block, we dont have to deal with the issue of variables getting hoised to the top of the function. In the example below, we are declaring i variable, its hoised to the top and when the inner function runs on nextTick they all see its last value and it prints the number 10, ten times.

 for(var i=0;i<10;i++){
   setTimeout(() => {
     console.log(i); // 10 10 10 10 10 10 10 10 10 10 
   }, 0)
 }

On the other hand, in the example below, we use let and there is no hoisting and each function has its j and they dont see any common j hoisted to the top. Therefore it prints the numnbers from 0 to 9.

 for(let j=0;j<10;j++){
   setTimeout(() => {
     console.log(j); // 0 1 2 3 4 5 6 7 8 9
   }, 0)
 }

To learn more about let: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let```

const is also block scoped like let and unlike var which is scoped to the function. Once created, a const can not be redefined and/or changed. Note, it doesn’t make the object it points to read-only. It merely prevent its reassignment.

Object property Definition

ES6 makes it a bit nice to define properties on objects as shown in the example below:

 var info = {first: 'sandeep', last: 'arneja'};
 var a = 1, b =2, c = 3;
 var foo = () => console.log('hi');
 var obj = {
   a, b, c, foo,
   name: 'sandeep',
   bar() {
     console.log("i am bar")
   },
   jones: () => console.log('i am jones'),
   ...info
 };
 
 console.log(obj);
 
 /*
 { a: 1,
   b: 2,
   c: 3,
   foo: [Function: foo],
   name: 'sandeep',
   bar: [Function: bar],
   jones: [Function: jones],
   first: 'sandeep',
   last: 'arneja' }
 */

import & Export

skipped as not supported natively in NodeJS NodeJS has its own module.exports concept which works great!

 // helper.js
 const add = (...args) => args.reduce( (accumulator, currentValue) => accumulator + currentValue );
 module.exports = add;

 // index.js
 const helper = require('./helper');
 console.log(helper(1,2,3)); // 6

In the case above add is the default export, in other words the function is the only thing exported.

When there are more than 1 item to return its better to return an object, like shown below:

  // helper.js
  const add = (...args) => args.reduce( (accumulator, currentValue) => accumulator + currentValue );
  module.exports = {add};
 
  // index.js
  const helper = require('./helper');
  console.log(helper.add(1,2,3)); // 6

Promises

A promise allows to return an object instead of asking to pass in a success and failure callback. This makes the code more linear and easier to read rather than having a right falling tree.

Without promises, if something was happening asynchronously, and we wished to run some code after it, we would pass in what we want to happen afterwards. These are known as callbacks and then we would trust that the async code will call our callback when the time is right.

Promises flip this setup on its head. Instead we expect the async function to return us a promise. We will then using the then keyword setup what we want to run after the async function has finished. See below how its done by using promises.

 const iAmAsyncFunction = () => {
    return new Promise( (resolve, reject) => {
      setTimeout( () => {
        console.log('after 1 second I will run and return data back');
        resolve(500)
      }, 1000)
    } );
 }
 
 iAmAsyncFunction().then(data => console.log('i got', data), undefined)

The function passed to the constructor of the Promise is called the executioner and it runs immediately and is passed in the resolve and reject methods. When these functions are called, their corresponding methods are called in the then method which has been called on the promise object.

Then takes 2 functions as parameters. 1st one is called when the promise its setup on is resolved and then 2nd one is called when the promise is rejected.

Understanding Chaining

Promises can be chained using then. This happens because each then return an implict promise which is resolved with the value returned by then. See example below:

const doSomething = () => {
  var p = new Promise( (resolve,reject) => {
    setTimeout(() => {
      console.log('doing something async which takes 2 seconds');
      resolve(100);
    }, 2000)
  });
  return p;
};

const moreDoing = data => {
  console.log("more doing immediately with: ", data);
  return 5;
}

const doSomethingMore = data => {
  console.log("doing something more immediately with: ", data);
  return 500;
}

doSomething().then(moreDoing).then(doSomethingMore);

In the code above, first the async function runs, after it is done each of the setup functions runs after the other. The reason then works on the return of then is because each then is returning a promise. This promise is implicitly being resolved with the value returned by the function its passed in. In our case that is moreDoing which returns 5 and therefor that then is returning a resolved promise with 5. Its like the then function is calling Promise.resolve(5) and returning that.

Now the function passed to then, may also doing async things and return a promise of its own. In the case, the next chained then just works off the explicitly returned promise by the function passed in to then. This works because Promse.resolve(aPromise) is the same as aPromise. Lets see an example:

const doSomething = () => {
  var p = new Promise( (resolve,reject) => {
    setTimeout(() => {
      console.log('doing something async which takes 2 seconds');
      resolve(100);
    }, 2000)
  });
  return p;
};

const moreDoing = data => {
  var p = new Promise( (resolve,reject) => {
    setTimeout(() => {
      console.log('moreDoing async which takes 2 seconds');
      resolve(500);
    }, 2000)
  });
  return p;
}

const doSomethingMore = data => {
  console.log("doing something more immediately with: ", data);
  return 5000;
}

doSomething().then(moreDoing).then(doSomethingMore);

Here the moreDoing explicitly returns a promise and then the next then is built on top of that promise. This means doSomething does not fire till moreDoing finished and resolved the promise it has returned.

Understanding implicit return in .then

Now lets explore how this implicitly returned promise from then works.

First lets take the case when we return a promise explicitly.

var p = new Promise((resolve, reject) => setTimeout(resolve, 2000))
p.then(() => console.log("its done")); 
var p = new Promise((resolve, reject) => setTimeout(resolve, 2000))
Promise.resolve(p).then(() => console.log("its done"));

Both the snippets of code above, do the exact same thing, even though in the 2nd one I called Promise.resolve on the promise p.

Now lets take the case when we return just a number and expect the implict promise to handle things.

var x = 5;
Promise.resolve(x).then(() => console.log("its done"));

The above code also works and runs immediately, therefore proving our point.

Understanding .catch

When promises are chained, they will look for their handler - success or failure and skip the chained items which dont defined their kind of handler. This is why adding a catch all the way at the bottom works. Its working because the previous then didnt define the failure handler.

  Promise.reject(1).
    then( () => {console.log('in then 1')}, undefined).
    then( () => {console.log('in then 1')}, undefined).
    catch( () => 'got the error' )

catch(fn) is shorthand for then(undefined, fn)

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises

Making an old-school non promise function, work with promises

We can wrap the old-school callback based function in a new function. In this new function we will call the old function and pass in a callback which will call resolve.

 // npm install ajax-request --save
 var request = require('ajax-request');
 
 request('https://www.google.com', function(err, res, body) {
   console.log('got status code', res.statusCode, ' and body length', body.length);
 });
 // got status code 200  and body length 46014
 
 var myRequest = url => new Promise( (resolve, reject) => {
   request(url, (err, res, body) => resolve({res, body}) )
 });
 
 myRequest('https://www.google.com').then( ({res, body}) => {
   console.log('got status code', res.statusCode, ' and body length', body.length);
 });
 // got status code 200  and body length 46950

Async/Await ECMA 2017

Read my detailed article here: http://sandeep45.github.io/redux/react/react-router/2019/02/11/aysnc_await.js.html

Generator

Generators are used to build generator functions. The generator function returns a value everytime next is called on it. It keeps returning the next yield and never the same one twice and stops once return is called.

function* even_numbers(){
  var num = 0;
  while(true){
    if(num > 10) {
      return num;
    }
    else {
      yield num;
    }
    num = num+2
  }
}

const nums = even_numbers();
console.log(nums);

console.log("manually: ", nums.next());
console.log("manually: ", nums.next());

for(let i of nums){
  console.log("from for-of loop", i);
}

/*
Object [Generator] {}
manually:  { value: 0, done: false }
manually:  { value: 2, done: false }
from for-of loop 4
from for-of loop 6
from for-of loop 8
from for-of loop 10
*/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator

Keyed Collection - Map & Sets

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Keyed_collections

Map

Javascript already has objects, which we have always been using as hashes. We can easily add properties to this object and access them like a dictionary. But now we have Map’s. Map’s allow:

  1. keys of any type, not just string like an object.
  2. iterating over the results in their insertion order by the use of an iterator. This means that new Map()[Symbol.iterator] is present and defined. So you can call next and/or use for-of loop.
  3. accessing the size of the hash.
 var hash = new Map();
 hash.set('name', 'sandeep');
 hash.set(1,2);
 hash.set(2,"arneja");
 console.log(hash.size);
 console.log(hash.get(2));
 
 console.log(hash.keys());
 console.log(hash.values());
 
 console.log(hash[Symbol.iterator]);
 const myIterator = hash[Symbol.iterator]();
 console.log(myIterator.next());
 console.log(myIterator.next());
 
 console.log('--');
 for(let i of hash){
   console.log(i);
 }
 
 /*
 3
 arneja
 [Map Iterator] { 'name', 1, 2 }
 [Map Iterator] { 'sandeep', 2, 'arneja' }
 [Function: entries]
 { value: [ 'name', 'sandeep' ], done: false }
 { value: [ 1, 2 ], done: false }
 --
 [ 'name', 'sandeep' ]
 [ 1, 2 ]
 [ 2, 'arneja' ]
 */

An object can be used to do all these things but without the nice helper things set provides, but if you truly need an object, which has methods, which can operator on other properties of that object and access the this keyword, then you should still use an object.

 var hash = {}
 hash['name'] = 'sandeep';
 hash['change'] = function() {
   this.name = 'arneja'
 }
 
 console.log(hash.name);
 hash.change();
 console.log(hash.name);

/*
sandeep
arneja
*/

WeakMap

Same like a set, just that the key's must be objects and will be garbage collected if they dont have any other reference to them. Also there is no way of getting list of keys, since key’s without reference should not exist, but may exist depedning on how the GC is feeling and therefore is non-deterministic.

It use is to store information about a key, without having memory leak, meaning that information should only be present as long as that key exists. This cant be dont with an array as an array would hold reference to they key, even after the key is no long reference by anyone else and is therefore of no use.

Use cases

https://stackoverflow.com/questions/29413222/what-are-the-actual-uses-of-es6-weakmap

If you want to add data about an object, but cant write in to that object, then store thata data in the WeakMap with the obect as the key. If you store it in a Map, or using 2 arrays, you will introduce a memory leak as your map or arrays will hold the value for every, even after that object ceases to exist. WeakMap’s solve this problem as the key ceases to exist in the weakmap as it allow garbage collection of its keys.

Set & WeakSet

This is the same as a regular set data structue. It only has values, all values are unique and can be iterated over in insertion order.

The same can be accomplished by using an array, but then you have to deal with smaller details like preventing duplicates, size etc.

A WeakSet, is the same, just that they keys can only be objects and maybe garbage collected when the key ceases to have any other reference.

Classes

Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes

My detailed article on classes here: http://sandeep45.github.io/es6/classes/javascript/2016/02/04/classes.html and for this go here: http://sandeep45.github.io/javascript/this/es6/fat-arrow/2016/02/03/this-keyword-in-javascript-part2.html

Body of a class runs in strict mode, so be aware. Body has space for 1 and only 1 constructor method which has access to super and can be used for object initialization.

super is used to call the same method from its super class.

extends is used for subclassing.

static puts methods on the class instead of the prototype.

ECMA2016 has ability to write bounded instance methods, but ES6 doesn’t.

User Object.setPrototypeOf() to have one object extend from another non-constructible object.

value of this will be undefined when methods are not called directly from the object. this is because its running in strict mode.

class Person {
  constructor(x,y){
    this.x = x;
    this.y = y;
  }

  sum() {
    if(this === undefined){
      console.log("unknown")
    }else{
      console.log(this.x+this.y);
    }
  }
}
const p = new Person(1,2);
p.sum();

const sum = p.sum;
sum();

/*
3
unknown
*/

Also not that when a method is defined like above, its being put on the prototype chain

console.log(Person.prototype.sum); // [Function: sum]

A Word on scope of this for methods

By default its scope-by-flow, so the value of this depends on the context from where its called

class Calculator {
  constructor(x,y){
    this.x = x;
    this.y = y;
   }
  sum() {
    return this.x+this.y;
  }
}
console.log(new Calculator(1,2).sum()); // 3

To prove that this is scope by flow, lets change how sum is called.

var me = {
  sum: new Calculator(1,2).sum,
  x: 5,
  y: 6
}

console.log(me.sum()); // 11

To solve this issue in ES7, change the function definition to use fat-arrow (=>) syntax and now this will only be resolved lexically.

In ES6, this can be solved by binding the function to this in the constrcutor, so that no matter where its called from, the value of this is what we want it to be.

class Calculator {
  constructor(x,y){
    this.x = x;
    this.y = y;
    this.sum = this.sum.bind(this); // money shoT!
   }
  sum() {
    return this.x+this.y;
  }
}

var me = {
  sum: new Calculator(1,2).sum,
  x: 5,
  y: 6
}

console.log(me.sum()); // 3 ! Boom !