Time for ES6

ES6 has changed the way JavaScript developers code nowadays. Great developers will take what's good in this update and throw away the rest.
This lesson focuses on the most important features, we will analyze some new tools like Generators, the new Promise object, how to use destructuration to accomplish fancy assignments, how the anonymous functions evolved, have a sneak peek into the Symbols and much more!

You can go to the ES6 console , JSFiddle or Plnkr to test it online.

Let's get started!

Constants that are inconstant

Since JavaScript is Object Oriented, when you see 'constant', you can think that your object is going to stay the same forever.

Well, not really.

This only concerns the primitive, if you want to make an object immutable, you need to use Object.freeze, example:

const A = { name: 1 };
Object.freeze(A);
A.name = 2; // fail

You can't be half a gangster

When ES6 get's high, we go low. - Matthieu Drula

Do you like CoffeeScript? Well ... they tried to get some inspiration there.

This is what most likely went through their mind:

"Guys, we might as well put some CoffeeScript like syntax in it since it's very compact and readable. We will not use curly brackets anymore".

let array1 = [1, 2, 3];
let sum = array1.map(value => value + 1);
// 2,3,4

audience-applause ES6

"Ahhh nevermind I already miss those lovely brackets, let's put them back.":

let array2 = [1, 2, 3];
array2.forEach(num => {
  if (num == 2) console.log("number 2 found");
});
sad-frog

All this fumble because of implicit return. If you only have one line of code, you can skip the brackets since the returned value can only be the result of this line, if not, you need to add them.

So. Quick test.

  1. Almost CoffeeScript (ES6):
let doSomething = x => {
  const a = x + 1;
  const b = a + 2;
  return b;
};
doSomething(1);
  1. CoffeeScript:
doSomething = (x) ->
  a = x + 1
  b = a + 2
  return b

doSomething 1

Which one do you want to bring to prom night? (Hint: Number 2).

The very useful ones

The spread operator

This feature might be very useful if you are working with Angular and the change detection doesn't kick in when you update an array.

This operator is a quick way to realize a concatenation or splitting a string:

const array1 = [1, 2, 3];
const array2 = [...array1, 4, 5];
// [1, 2, 3, 4, 5]
const name = "Matthieu";
const chars = [...name];
// M,a,t,t,h,i,e,u

Multiline strings and variable interpretation

ES6 finally brought something that has been present for years in other languages and was dreadfully missing in JavaScript. By using the backquote symbol, you can break lines and indent your strings. You can also combine that with the use of ${} in order to use some variables.

let variableHere = "just a variable";
let a = `some text
${variableHere}
other text`;

Export/Import

It's something that you must have encountered if you have read other articles about Angular.

Here is an example:

export var a = 1;
export cb = function(x,y) {
  console.log(x,y);
}
import { a, cb } from "somewhere/over/the/rainbow";
cb(a, a);

//Or
import * as importedModule from "somewhere/over/the/rainbow";
importedModule.cb(importedModule.a, importedModule.a);

Property Shorthand

This one is by far my favourite.

Before:

const obj = {
  variableWithAnnoyingLongName: variableWithAnnoyingLongName,
  anotherVariableWithAnnoyingLongName: anotherVariableWithAnnoyingLongName
};

Now with ES6:

const obj = {
  variableWithAnnoyingLongName,
  anotherVariableWithAnnoyingLongName
};

Combined with the new Function Signature feature it gets more powerful!

Function Signature

We can now assign the parameters of a function:

  • By default ex: doSomething(a=1, b=2)
  • By destructuring:

    const arr1 = [1, 2, 3];
    function destructure([a, b]) {
      console.log(a, b);
      //1 2
    }
    destructure(arr1);
    
  • By changing the arguments names ex: f({a: name, b: age})

  • Or by selecting them with a shorthand ex: f({name, age})

So now we can do cool things like:

function doSomething({ age, name, id }) {
  console.log(age, id, name);
  //26 2
}
const age = 26;
const id = 2;

doSomething({ age, id });

The controversial one

Do you like JAVA? Well ES6 is now JAVA. Period. Next.

Joke aside.

There are many features that have been stolen implemented from JAVA. The most obvious ones:

  • Classes:

    class Animal {
      constructor(id, name) {
        this.id = id;
        this.name = name;
      }
    }
    
  • Inheritance:

    class Bird extends Animal {
      constructor(id, name, featherType) {
        super(id, name);
        this.featherType = featherType;
      }
    }
    

Eric Elliott said about classes that they are "the marauding invasive species" you can (must) have a look at his well-described article here.

If you are ready to fight for your own style, prepare to receive friendly-fire from many of your colleagues.

javascript inheritance troll

Generators

One of the coolest features that ES6 brings is the Generator. Now you can say **** you to the asynchronous aspect of JavaScript.

By creating a Generator function using the '_' character, you can pause the execution of a method at a 'yield' keyword. To resume the execution of the method, you need to grab the returned generator and call the method named next.

Here is an example where I yield the method at an asynchronous action then unpause it once I got the awaited result:

function getIdInDb() {
  // Simulate async Db request
  setTimeout(function() {
    tmp.next(2); // I return 2 as a result for my Id
  }, 2000);
}

// Use the id returned by the yielded function
function getUserWithId(id) {
  console.log("Getting user with id:", id);
}

function* doSomethingInTheDb() {
  let id = yield getIdInDb();
  console.log("The id is:", id);
  getUserWithId(id);
}

// Stock the generator
var tmp = doSomethingInTheDb();

// Trigger the first yield
tmp.next();

Promises

No need to use $q or whatever 3rd party library anymore. Now you can just use a Pure JavaScript Promise like this:

var promise = new Promise((resolve, reject) => {
  resolve("success");
});

function handleSuccess(result) {
  console.log("success", result);
}

function handleError(err) {
  console.log("error", err);
}

promise.then(handleSuccess, handleError);

Destructuring

Destructuring is quite a touchy part of ES6 because it can make or break a developer. The major change of philosophy here is to accept that there might be some holes in the signatures, we generally try to fill those holes using null or undefined, so here the greatest challenge is to lose this “perfectionism“.

Here are some examples with an incremental difficulty:

const [a, b, c] = [1, 2, 3];
console.log(b); // 2

const [d, , f] = [4, 5, 6];
console.log(f); // 6

const { id, surname, name } = { age: 26, name: "Matthieu" };
console.log(name); // Only name is defined so: Matthieu

const { test = "Default value" } = {};
console.log(test);
// Default value

const { address } = { address: { street: "Here", city: "There" } };
console.log(address);
// Object {street: "Here", city: "There"}

You can also couple it with the shorthand feature.

Anonymous functions

A very quick one here, if you are just like me and don’t like the syntax for anonymous functions, you can replace it by simply using {} instead of (function () {})();

Just like this:

function sayHi() {
  console.log("hi 1");
}
{
  function sayHi() {
    console.log("hi 2");
  }
}
sayHi();

Symbols

Another controversial feature here: the Symbols.

Just like many people, I think that there is something missing in this feature.
This feature was stolen created in order to prevent name clashing when manipulating objects.

An example of name clashing looks like this.

Someone access the object foo and use the key bar. Just after that you do the same and overwrite this property. That’s quite annoying right? And this is because the key is a String.
A symbol is very helpful in this case. A symbol is not private but it is collision free. Name clashing using Symbols is like burning down your house with a flamethrower then saying that you only forgot to put out a candle before sleeping.

Here is an example showing how to use Symbols to prevent collisions.

By keeping the symbol inside of the object we can limit the public manipulation of a property:

var Person = (function() {
  var ageSymbol = Symbol("age");
  function Person(age) {
    this[ageSymbol] = age;
  }
  Person.prototype.getAge = function() {
    return this[ageSymbol];
  };
  return Person;
})();

var a = new Person(26);
console.log(a.getAge()); //Output: 26
a.age = null;
console.log(a.getAge()); //Output: 26

Nice isn’t it?

Unfortunately, it’s not perfect. Mainly because it’s not private. You can literally grab a symbol whenever you want, wherever you want:

let obj = {};

var symb = Symbol.for("Symbol");
obj[symb] = "supposed to be hidden";
console.log(obj[symb]); // 'supposed to be hidden'

var sameSymb = Symbol.for("Symbol");
console.log(symb === sameSymb); //true

Since you can grab the symbol from anywhere, you can overwrite the data whenever you want, just like this:

obj[sameSymb] = "Your data just got overwitten";
console.log(obj[symb]); //Your data just got overwitten

Conclusion

ES6 comes with new features that make JavaScript looks like a different language.
Some features are really easy to use like the multi line strings. Others will however require a little bit of time to master like the use of constants.

We have seen here some powerful tools like Generators and Desctructuring Assignement that transform the way we code nowadays and in the future. Moreover, some features like Async in ES7 are inspired by features from ES6 (Generators in this case), hence those new principles will be propagated in the future implementations of JavaScript.

Some are good to know, like Vanilla JavaScript Promises and some are literally ignored like Symbols.