ES6 Main Functionalities

Let's have a look at some of the most interesting features of ES6.

Scroll down...

Content

Resources

Comments

So ES6 indeed made some waves even before it was standardized and definitely paved the way for the next standards. The entire JavaScript community can now rely on the language being formally advanced every year. Let's take a look together at some of the most useful functionalities of ES6 (Note: this is not an exhaustive list, but a mere selection of some of the most widely used goodies of the language).

Let and Const

Forget var. That's something you don't need to use from now on. That doesn't mean you will just let your variables lying around in the codebase without any declaration in front. No, no! We'll be using let and const from now on.

let and const are the new var which allows to scope the variable to the blocks. We define blocks by the curly braces. In ES5, the blocks did NOTHING to the vars:

function calculateTotalAmount (vip) {
  var amount = 0;
  if (vip) {
    var amount = 1;
  }
  {
    // more crazy blocks!
    var amount = 100;
    {
      var amount = 1000;
    }
  }  
  return amount;
}

console.log(calculateTotalAmount(true));

The result will be 1000. Wow! That’s a really bad bug. In ES6, we use let to restrict the scope to the blocks. Variables now become function scoped.

function calculateTotalAmount (vip) {
  var amount = 0;
  if (vip) {
    let amount = 1;
  }
  {
    // more crazy blocks!
    let amount = 100;
    {
      let amount = 1000;
    }
  }  
  return amount;
}

console.log(calculateTotalAmount(true));

The value is 0, because the if block also has let. If it had nothing (amount = 1), then the expression would have been 1.

When it comes to const, things are easier; it’s just an immutable (almost), and it’s also block-scoped like let. We say it's almost an immutable (despite the name), because this only makes the variable itself immutable, not its assigned content (for instance, in case the content is an object or an array, this means the object/array itself can still be altered). Also, unlike let, const needs to be initialized.

const a; // Can't do that => Uncaught SyntaxError: Missing initializer in const declaration

const a = 3;
a = 2; // Can't do that => Uncaught TypeError: Assignment to constant variable.

const a = {};
a = 2; // Still can't do that => Uncaught TypeError: Assignment to constant variable.
a.name = 'Viking'; // But I can do this!

Arrow Functions

Arrow functions are available to many other modern languages and was one of the features that was missed in JavaScript for a long time. Fortunately, they’re now part of ES6 and thus available to us. The syntax is quite expressive. We already had anonymous functions, but sometimes it’s nice to have a terse alternative.

Here’s how the syntax looks like if we have a single argument and just want to return the results for an expression (alongside ES5 equivalent):

// ES6 arrow function
[1, 2, 3].map(num => num * 2)
// <- [2, 4, 6]


// ES5 implementation
[1, 2, 3].map(function (num) { return num * 2 })

If we need to declare more arguments (or no arguments), we’ll have to use parenthesis.

[1, 2, 3, 4].map((num, index) => num * 2 + index)
// <- [2, 5, 8, 11]

You might want to have some other statements and not just an expression to return. In this case you’ll have to use bracket notation. You could also add more arguments with the parenthesis syntax.

[1, 2, 3, 4].map((num, index) => {
  var multiplier = 2 + index
  return num * multiplier
})
// <- [2, 6, 12, 20]

However, there's a small catch here. If we need to return an object literal, we’ll have to wrap the expression in parenthesis. That way the object literal won’t be interpreted as a statement block (which would result in a silent error or worse, a syntax error because number: n isn’t a valid expression in the example below.

[1, 2, 3].map(n => { number: n, something: 'else' })
// <- SyntaxError

[1, 2, 3].map(n => ({ number: n, something: 'else' }))
/* <- [
  { number: 1, something: 'else' },
  { number: 2, something: 'else' },
  { number: 3, something: 'else' }]
*/

A cool aspect of arrow functions in ES6 is that they’re bound to their lexical scope. That means that you can say goodbye to var self = this and similar hacks – such as using .bind(this) – to preserve the context from within deeply nested methods. Keep in mind that the lexical this binding in ES6 arrow functions means that .call and .apply won’t be able to change the context. Usually however, that’s more of a feature than a bug.

function Timer () {
  this.seconds = 0
  setInterval(() => this.seconds++, 1000)
}
var timer = new Timer()
setTimeout(() => console.log(timer.seconds), 3100)
// <- 3

Destructuring

Destructuring is also one of the simplest and nicest features of ES6. It binds properties to as many variables as you need and it works with both Arrays and Objects. Let's see a quick example:

const foo = { bar: 'pony', baz: 3 };
const {bar, baz} = foo;
console.log(bar);
// <- 'pony'
console.log(baz);
// <- 3

You can also pull properties as deep as you want, and you could also alias the bindings no matter the level (as you can see in the example below):

const foo = { bar: 'pony', baz: 3 }
const {bar: a, baz: b} = foo
console.log(a)
// <- 'pony'
console.log(b)
// <- 3

One particular use for destructuring that comes up a lot is related to swaping variables. Gone are the days when you had to use an aux variable as an intermediary. In ES6 you can do something like:

const swap = () => {
  let left = 10;
  let right = 20;
  if (right > left) {
    [left, right] = [right, left];
  }
  // ... more code
}

Destructuring is great and there are a lot of use cases when it comes in handy.

Rest and Spread Operators

We know how sometimes there are a ton of arguments and we end up having to use the arguments magic variable to work with them? Consider the following method that joins any arguments passed to it as a string.

function concat() {
  return Array.prototype.slice.call(arguments).join(' ')
}
const result = concat('this', 'was', 'no', 'fun')
console.log(result)
// <- 'this was no fun'

The rest parameters syntax enables you to pull a real Array out of the function's arguments by adding a parameter name prefixed by .... Definitely simpler and the fact that it’s a real Array is also very convenient. Let's see an example:

function concat(...words) {
  return words.join(' ')
}
const result = concat('this', 'is', 'okay')
console.log(result)
// <- 'this is okay'

When we have more parameters in your function it works slightly different. Whenever we declare a method that has a rest parameter, its behavior is as follows:

  • Rest parameter gets all the arguments passed to the function call
  • Each time a parameter is added on the left, it’s as if its value is assigned by calling rest.shift()
  • Note that we can’t actually place parameters to the right: rest parameters can only be the last argument

Here's an example take makes use of the logic above:

function sum (multiplier, base, ...numbers) {
  console.log(numbers);
}
sum(2, 6, 10, 8, 9)
// <- [10, 8, 9]

The spread operator can be used as a butter knife alternative over using .apply. It is always used in conjunction with an Array. You just append three dots ... to the array, just like with the rest parameter.

console.log(...[1, 2, 3])
// <- '1 2 3'

Another nice aspect of this butter knife operator is that you can mix and match regular arguments with it, and they’ll be spread over the function call exactly how you’d expect them to. This, too, can be very very useful when you have a lot of argument rebalancing going on in your ES5 code.

console.log(1, ...[2, 3, 4], 5) // becomes `console.log(1, 2, 3, 4, 5)`
// <- '1 2 3 4 5'

Default Parameters

Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed. In JavaScript, parameters of functions default to undefined. However, in some situations it might be useful to set a different default value. This is where default parameters can help.

In the past, the general strategy for setting defaults was to test parameter values in the body of the function and assign a value if they are undefined. If in the following example, no value is provided for b in the call, its value would be undefined when evaluating a * b and the call to multiply would have returned NaN. However, this is caught with the second line in this example:

function multiply(a, b) {
  b = (typeof b !== 'undefined') ?  b : 1;
  return a * b;
}

multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5);    // 5

With default parameters in ES6, the check in the function body is no longer necessary. Now, you can simply put 1 as the default value for b in the function head:

function multiply(a, b = 1) {
  return a * b;
}

multiply(5, 2); // 10
multiply(5, 1); // 5
multiply(5);    // 5

Ain't that a cool feature?

Template Literals

Template literals are a new feature in ES6 to make working with strings and string templates easier. You wrap your text in backticks and you’ll get the features described below.

  • You can interpolate variables in them
  • You can actually interpolate using any kind of expression, not just variables
  • They can be multi-line. Finally!
  • You can construct raw templates that don’t interpret backslashes

Let's see an example of interpolation in action:

var host = 'vikingcodeschool.com'
var text = `this blog lives at ${host}`
console.log(text)
// <- 'this blog lives at vikingcodeschool.com'

The following expressions would all work just as well. It’ll be up to us to decide how much logic we cram into the interpolation expressions.

var text = `this blog lives at ${'vikingcodeschool.com'}`
console.log(text)
// <- 'this blog lives at vikingcodeschool.com'

var today = new Date()
var text = `the time and date is ${today.toLocaleString()}`
console.log(text)
// <- 'the time and date is 8/26/2015, 3:15:20 PM'

And finally, multi-line strings mean that you no longer have to use weird methods like join() anymore.

var text = (
  `
    foo
    bar
    baz
  `
);

Template literals are very powerful and they open doors to endless possibilities. Who know? You might not even use quotes from now on, right?

Wrapping Up

ES6 definitely made an impact. The sheer number of additions to the language promulgated JavaScript as one of the top choices for a programming language nowadays. In this lesson, we covered some of the most used features of the language. So now, that you're armed with this knowledge, it's time to put it to work!



Sign up to track your progress for free

There are ( ) additional resources for this lesson. Check them out!

There are no additional resources for this lesson just yet!

Sorry, comments aren't active just yet!