Arrows

A function shorthand that binds this value. Arrow functions are always anonymous.

 
  // // Basic syntax:
  // (param1, param2, paramN) => { statements }
  // (param1, param2, paramN) => expression
  // equivalent to:  => { return expression; }

  // Parentheses are optional when there's only one argument:
  // singleParam => { statements }
  // singleParam => expression

  // A function with no arguments requires parentheses:
  // () => { statements }

  // Advanced:
  // Wrap an object literal expression in parentheses
  // params => ({foo: bar})

  // Rest parameters are supported
  // (param1, param2, ...rest) => { statements }

  var names = [
    {
      first: 'john',
      last: 'doe'
    },
    {
      first: 'harry',
      last: 'potter'
    },
    {
      first: 'wee',
      last: 'kee'
    }
  ];

  names.map( name=> name.first + name.last );

classes: does not introduce a new way rather is a sugar syntax

A difference between function declarations and class declarations is that function declarations are hoisted and class declarations are not. You first need to declare your class and then access it, otherwise code like the following will throw a ReferenceError:

  var p = new Polygon(); // ReferenceError

  class Polygon {
    constructor(height, width) {
      this.height = height;
      this.width = width;
    }
    // A class can also define a property with get and set to encapsulate a field.
    get area() {
      return this.calcArea()
    }

    calcArea() {
      return this.height * this.width;
    }
    
    static distance(a, b) {
      console.log('I am a static function');
      console.log('I do not give shit about instances');
    }
    
  }

Tell me about inheritance

  class Cat { 
    constructor(name) {
      this.name = name;
    }
    
    speak() {
      console.log(this.name + ' makes a noise.');
    }
  }

  class Tiger extends Cat {
    speak() {
      super.speak();
      console.log(this.name + ' roars.');
    }
  }

  var d = new Tiger('Simba'); // Tiger {name: "Simba"}
  console.log(d);             // Simba makes a noise.
  console.log(d.speak());     // Simba roars.

Enhanced Object Literals

  var theProtoObj = {
    name: 'whatever',
    age: -1
  };

  var handler = function() {};

  var obj = {
      // __proto__
      __proto__: theProtoObj,
      // Shorthand for ‘handler: handler’
      handler,
      // Methods
      toString() {
       // Super calls
       return "d " + super.toString();
      },
      // Computed (dynamic) property names
      [ 'prop_' + (() => 42)() ]: 42
  };

Template Strings

  var name = "Bob", time = "today";

  // and even this is possible
  console.log(`Hello ${name}, how
  are
  you ${time}?`);

Destructuring

  var foo = ["one", "two", "three"];
  var [one, two, three] = foo;

  var a,b;
  [a, b] = [1, 2];

multiple returns

  var func = function() {
    return [1, 2];
  };

  var [a, b] = func();

  var {p, q} = {p: 42, q: true};

  console.log(p); // 42
  console.log(q); // true 

  // Assign new variable names
  var {p: foo, q: bar} = {p: 42, q: true};

  console.log(foo); // 42
  console.log(bar); // true

Default

  function f(x, y=12) {
    // y is 12 if not passed (or passed as undefined)
    return x + y;
  }

  f(3); // 15;

Rest Parameters

  function f(x, ...y) {
    // y is an Array
    return x * y.length;
  }

  f(3, "hello", true);  // 6;

Symbol:

A unique and immutable data type and may be used as an identifier for object properties. It is an implicit object wrapper for the symbol primitive data type.

  var fooSym = Symbol('foo');  
  var myObj = {};  
  myObj['foo'] = 'bar';  
  myObj[fooSym] = 'baz';  
  Object.keys(myObj); // -> [ 'foo' ]  
  Object.getOwnPropertyNames(myObj); // -> [ 'foo' ]  
  Object.getOwnPropertySymbols(myObj); // -> [ Symbol(foo) ]  
  assert(Object.getOwnPropertySymbols(myObj)[0] === fooSym);  

Symbol.for: not unique

There is also another way to make Symbols - Symbol.for() This method creates a Symbol in a “global Symbol registry”.

  var myObj = {};  
  var fooSym = Symbol.for('foo');  
  var otherSym = Symbol.for('foo');  
  myObj[fooSym] = 'baz';  
  myObj[otherSym] = 'bing';  
  assert(fooSym === otherSym);  
  assert(myObj[fooSym] === 'bing');  
  assert(myObj[otherSym] === 'bing');

Symbol: Usage

  var Pet = (function() {
    var typeSymbol = Symbol('type');
    function Pet(type) {
      this[typeSymbol] = type;
    }
    Pet.prototype.getType = function(){
      return this[typeSymbol];
    }
    return Pet;
  }());

  var a = new Pet('dog');
  
  a.getType();    // dog
  a.type = null; // stays private
  a.getType();  // dog

Iterator and Iterable

  let arr = ['a', 'b', 'c'];          // array is iterable
  let iter = arr[Symbol.iterator]();  // iter is iterator

  iter.next() // { value: 'a', done: false }
  iter.next() // { value: 'b', done: false }
  iter.next() // { value: 'c', done: false }
  iter.next() // { value: undefined, done: true }

  // By default, objects are not iterable
  // but we can try
  let a = {name: 'hmmm', age: 23, address: {city: 'ny', state: 'bihar'}};

  // add iterator function
  a[Symbol.iterator] = function() {
      var nextIndex = 0;
      var keys = Object.keys(this);
      var self = this;

      return {
         next: function(){

             return nextIndex < keys.length ?
                 {value: self[keys[nextIndex++]], done: false} :
                 {done: true};
         }
      };  
  };

  var it = a[Symbol.iterator]();

  console.log(it.next());
  console.log(it.next());
  console.log(it.next());
  console.log(it.next());

For - of

  for (let x of ['a', 'b']) {
      console.log(x);
  }
  // Output:
  // 'a'
  // 'b'

  let map = new Map().set('a', 1).set('b', 2);
  for (let pair of map) {
      console.log(pair);
  }
  // Output:
  // ['a', 1]
  // ['b', 2]

  for (let x of {}) { // TypeError
      console.log(x);
  }

Sets

  var s = new Set();
  s.add("hello").add("goodbye").add("hello");
  s.size === 2;
  s.has("hello") === true;

Maps

  var m = new Map();
  m.set("hello", 42);
  m.set(s, 34);
  m.get(s) == 34;

WeakMaps

  // provides leak-free object-key’d side tables.
  var wm = new WeakMap();
  wm.set(s, { extra: 42 });
  wm.size === undefined

Weak Sets

  var ws = new WeakSet();
  ws.add({ data: 42 });
  // Because the added object has no other references,
  // it will not be held in the set.

Newly added APIs

  'hello'.startsWith('hell') // true
  'hello'.endsWith('ello') // true
  'hello'.includes('ell') // true
  'doo '.repeat(3)      // 'doo doo doo '

Array.from

  // Convert array-like structure to array
  let lis = document.querySelectorAll('ul.fancy li');
  Array.from(lis).forEach(function (li) {
      console.log(node);
  });
   
  Array.from([ 'a', 'b' ].keys()) // [ 0, 1 ]
  Array.from([ 'a', 'b' ].values()) // [ 'a', 'b' ]
  Array.from([ 'a', 'b' ].entries()) // [ [ 0, 'a' ], [ 1, 'b' ] ]

Now the much awaited - Generators

They are mystical, nobody have seen them but some people say that they looks like a function though do not behave like them. Well, that’s strange. Let me tell you the long story short. With ES6 generators, we have a different kind of function, which may be paused in the middle, one or many times, and resumed later, allowing other code to run during these paused periods. So they kind of use yield keyword to stop where ever they want ( like a debugger in Chrome ). Let’s see that in action.

  function *foo() {
      var x = 1 + (yield "foo");
      console.log(x);
  }

  let it = foo();
  it.next();  // reutrns { done: false, value: "foo" }
  it.next();     // prints x as NaN and returns { done: true, value: undefined }
  // now once all the yields are done 
  it.next();    //  returns { done: true, value: undefined }

  function *foo() {
      yield 1;
      yield 2;
      yield 3;
      yield 4;
      yield 5;
  }

  let it = foo();
  it.next(); // { value:1, done:false }
  it.next(); // { value:2, done:false }
  it.next(); // { value:3, done:false }
  it.next(); // { value:4, done:false }
  it.next(); // { value:5, done:false }
  it.next(); // { value:undefined, done:true }

Till now we have only seen Generators yielding something everytime, but there is more to it - you can talk too.

  function *foo(x) {
      var y = 2 * (yield (x + 1));
      var z = yield (y / 3);
      return (x + y + z);
  }

  var it = foo( 5 );

  // note: not sending anything into `next()` here
  it.next();       // { value:6, done:false }
  it.next( 12 );   // { value:8, done:false }
  it.next( 13 );   // { value:42, done:true }