Skip to content

Instantly share code, notes, and snippets.

@cjus
Last active October 20, 2015 11:12
Show Gist options
  • Save cjus/42e7793c62c3bd276e63 to your computer and use it in GitHub Desktop.
Save cjus/42e7793c62c3bd276e63 to your computer and use it in GitHub Desktop.
Playing with ES6

A few words about this presentation

ECMAScript is a scripting language specification and standard from which JavaScript, JScript and ActionScript are popular implementations. ECMAScript version 5.1 (ES5) is the current version used in JavaScript implementations found in modern web browsers. In this presentation we'll refer to ES5 as the current version of JavaScript and ES6 as the newer version.

There are over one hundred new features in ES6. This presentation focuses, instead, on helping to prepare you to write, build and test ES6 code. Along the way we'll definitely look at actual code samples

I've also choosen to present ES6 features which are relatively easy to grasp so that your onramp to ES6 isn't unnecessarily complicated. As you gain experience with ES6 you'll learn about more complex features. Remember that the power of any language is realized in how the features come together to become much more than the sum of their parts. So definitely take the time to learn as many of the new features as you can.

JavaScript rising

JavaScript, which is now roughly 18 years old, has become the de facto language of the web. Today, complete, full-stack applications can be built entirely in JavaScript. Additionally, JavaScript is no longer restricted to use on the web. It's also playing an active role in backend infrastructure and is being used in the internet of things (IoT) powering smart small devices.

Last June, the sixth edition of ECMA-262 was published. That marks the official release of the standards specification document. Browser manufacturers have been working to implement aspects of the new standard as they've been introduced. So at the time of this presentation there is still work to do to fully implement each and every feature outlined in the specification.

As a result, there is currently a gap between what's in the final published specification and what is available in browsers and in NodeJS. Tools, called transpilers, have been built to fill this gap, by allowing us to program using new ES6 features and having our code translated into existing ES5 JavaScript code so it runs in modern browsers and on Node.

So this is a great time to get started with ES6! As you learn the new language features you'll be able to readily apply it in your own code. As the features are implemented in browsers they'll also be optimized for performance. So things only get better from here!

So what's really the big deal?

You might be wondering what is really the big deal with ES6? The new features of ES6 will make the JavaScript language less error prone and much more powerful. To be fair, many of the new features are influenced by other programming languages such as Ruby and Python. So in some ways this next iteration of JavaScript makes it easier for other programmers to embrace JavaScript.

How do you know which ES6 features are ready for use?

A common question that arises among programmers new to ES6 is "how do I know which ES6 features I can use today?"

Transpilers are currently the best best in terms of allowing you to use features which are not widely availble. So in this presentation we'll focus on using transpilers as they'll help you learn the new ES6 features without having to wait until they're in every browser.

Trying ES6 without installing software

There are literally no obstacles to getting started with ES6. To get started you don't even need to install any software.

Simply point your web browser to one of these addresses to begin trying ES6. You can enter all of the examples you'll find in this presentation and on the web.

Definitely try both of these links. I prefer the babel repl because it not only runs your ES6 code it also shows you the ES5 translated output. This gives you a view into what the transpiled code will be on web browsers that don't fully support ES6. By the end of next year you won't have to use a transpiler.

Building ES6 locally

After you're done playing with ES6 fiddle and the Babel online REPL you might want to transpile your ES6 locally and perhaps start using it in your projects.

Both Babel and Traceur provide tools for transpiling ES6 to ES5. We'll look at Babel, but you're free to also checkout Traceur.

First make sure you have NodeJS installed. If not, checkout https://nodejs.org

Next install babel using NPM:

sudo npm install -g babel

Here we're installing babel globally using the -g flag so we we'll be able to use babel in lots of projets.

With babel installed, create a test folder:

$ mkdir es6
$ cd es6
$ mkdir src
$ mkdir dest

So we create a folder called es6 and then create two sub-folder, src and dest. The src folder is where we'll add our ES6 source files. The dest folder is where we'll have Babel write the transpiled ES5 code.

Let's try this. Go to the src folder and create a helloES6.js file with the following content:

const helloMessage = 'Hello ES6';
console.log(helloMessage);
helloMessage = "can't touch this!";

Go back up to the project root and then run the bable command:

$ cd ..
$ babel src --out-dir dest

We first tell bable that it should look for JavaScript files in the src folder, then we use the --out-dir flag to specify the output destination folder. In our case, dest.

If we try to run this we get an error.

SyntaxError: src/helloES6.js: Line 3: "helloMessage" is read-only
  1 | const helloMessage = 'Hello ES6';
  2 | console.log(helloMessage);
> 3 | helloMessage = "can't touch this!";
    | ^
  4 |

The problem is that we've used a new ES6 const keyword to declare a read-only constant string, helloMessage. After displaying the message with console.log we try to change the const message to "can't touch this!". Sure enough this generates and error.

To fix the problem simply comment or remove the last line.

We can use node to run our transpiled JavaScript code:

$ cd dest
$ node helloES6.js

This is the basics for how ES6 code is transpiled and executed. Improvements to this include automating this build process using Node or a build tool such as Grunt, Gulp or a packaging tools such as Webpack.

Let's look at a quick way to add some automation using Babel. We can ask babel to hang around and watch for file changes so that as we change files in our src folder - babel will automatically transpile them into our dest folder.

$ babel src --out-dir dest --watch

Now we can open another terminal window and update our helloES6.js file to see this in action.

Exploring ES6 features

let keyword

JavaScript is known as a function scope language as opposed to being block scope language. In block scoped languages (such as C++, C# and Java) the introduction of curly braces ({}) introduces a new scope.

Consider this C++ program:

#include <iostream>

using namespace std;

int main()
{
  int i = 42;

  if (i == 42) {
    int i = 64;
  }

  cout << i << endl;
}

The output is 42 because the curly braces after the if statement introduces a new scope and a new 'i' value. That value, 64, doesn't interfere with the original declaration of i, which is 42. Scope is introduced using loop structures such as for, while, do.

Because JavaScript is a function scoped language the following code doesn't do what block language users might expect. In this JavaScript version the output is instead 64. The reason is because only a function introduces a new scope and not the curly braces in the if statement.

var i = 42;

if (i == 42) {
  var i = 64;
}

console.log(i);

In ES6 we have a the let keyword which scopes a variable to the nearest curly braces.

var i = 42;

if (i == 42) {
  let i = 64;
}

console.log(i);

Now, the output value of 'i' is 42, because the 'i' created using the let statement is scoped to the if statement.

A common scenario is when we write the follow piece of JavaScript. Here we don't expect the value of 'i' to be used outside the four loop.

for (var i = 0; i < 5; i += 1) {
  // do something with i
}

console.log('The value of i is', i);

The output is that 'i' is defined and has a value of 5.

Replacing the var keyword with the let keyword results in 'i' being undefined.

for (let i = 0; i < 5; i += 1) {
  // do something with i
}

console.log('The value of i is', i);

Proper use of let will result in cleaner, let error prone code.

Const keyword

The const keyword is used to declare read-only variables. That is, variables who's content can not be changed. Like the let keyword, const is blocked scoped. We saw the use of the const keyword earlier when we looked at transpiling ES6 code locally using Babel.

const helloMessage = 'Hello ES6';
helloMessage = "can't touch this!";

Default parameters

Prior to ES6, JavaScript didn't have a native way of specifying default function parameters. So it's common to see code like this:

function sayHello(message) {
  var message = message || 'Hello';
  console.log(message);
}

sayHello();

The var line essentially says: message is equal to message if one is provided otherwise, message is 'Hello'.

With ES6, we're able to specify default function parameters:

function sayHello(message = 'Hello') {
  console.log(message);
}

sayHello();

Notice how much cleaner that is!

Rest parameters

In ES5 if we wanted to write a function which accepts a variable number of parameters we'd have to use the arguments object.

function sum() {
   var numbers = Array.prototype.slice.call(arguments),
       result = 0;
   numbers.forEach(function (number) {
       result += number;
   });
   return result;
}
console.log(sum(1));             // 1
console.log(sum(1, 2, 3, 4, 5)); // 15

While this works, there are a number of things which make this appraoch far from ideal.

  • You can't easily tell that the sum function actually accepts any parameter.
  • Unless you're familiar with this bit of boilerplate you may not b clear on what Array.prototype.slice.call is actually doing.

ES6 comes to the rescue with the rest operator.

function sum(…numbers) {
  var result = 0;
  numbers.forEach(function (number) {
    result += number;
  });
  return result;
}
console.log(sum(1)); // 1
console.log(sum(1, 2, 3, 4, 5)); // 15

The ... rest operator converts passed function parameters into an array called numbers, which we can then iterate using the forEach array member.

Spread operator

The spread operator looks like the rest operator because it also uses ... (ellipses) syntax.

Spread allows you to spread the values of an array back to function parameters.

Here's an example:

var a3DCoordinate = [100.2, 213.44, 50.34];

function set3DCoordinate(x, y, z) {
  console.log('spaceship set to', x, y, z); 
}

set3DCoordinate(...a3DCoordinate);

String templates

In earlier versions of JavaScript we've concatenated strings using the plus (+) operator.

var user = 'Dave';
var message = 'Hello ' + user + ', I am the HAL 9000.';
console.log(message);

With ES6 we can use string templates to compose strings:

var user = 'Dave';
var message = `Hello ${user}, I am the HAL 9000.`;
console.log(message);

There are a few things to note in the string template above. First we're not using the single quote character we know and love, rather we're using the Grave character, which is also known as the backtick character.

As an aside, you can pronounced grave as grave, but that's a bit morbid. Also, in the JavaScript context it's actually bringing strings to life rather than deleting them. Ok, back to our regularly scheduled program.

The second thing to note in the string template is that we're using dollar and curly braces to denote variables which should be used to insert data into our created string.

The dollar curly syntax isn't only useful with variables, you can also use expressions.

var age = 42;
var daysInYear = 365;
var message = `You are about ${age * daysInYear} days old.`;
console.log(message);

Another cool thing you can do is build multiline templates:

var user = 'Dave';
var message = `Hello ${user}.
I am the
HAL 9000.`;
console.log(message);

This example wont appear in the ES6Fiddle tool, but you can see it work in the Babel Repl: http://babeljs.io/repl

You'd see this:

Hello Dave.
I am the
HAL 9000.

As you can imagine the use of the grave (`) character is necessary to avoid collision with the single (') character. If you accidentally used the single character you'd see an error message such as:

Unterminated string constant

For can also create a custom function for parsing and building complex templates. Lets say we want to introduce a bit of logic to an order form.

var purchaseAmount = 500;
var size = 'large';
var message = `Thank you for your ${size} purchase.`;
console.log(message);

However we want to replace size with 'small', 'medium' or 'large' based on the purchaseAmount. We could do this:

var purchaseAmount = 500;
var size;

if (purchaseAmount <= 20) {
  size = 'small';
} else if (purchaseAmount > 20 && purchaseAmount <= 50) {
  size = 'medium';
} else {
  size = 'large';
}
var message = `Thank you for your ${size} purchase.`;
console.log(message);

However, using ES6 you might think you can cleanup your code by placing the logic in a function and then calling the function from the template:

var purchaseAmount = 500;
var size;

function purchaseSize(amount) {
  if (purchaseAmount <= 20) {
    size = 'small';
  } else if (purchaseAmount > 20 && purchaseAmount <= 50) {
    size = 'medium';
  } else {
    size = 'large';
  }
}

// NOTE: this won't work!
var message = `Thank you for your ${purchaseSize(purchaseAmount)} purchase.`;
console.log(message);

Running that code in the Babel Repl would return:

Thank you for your undefined purchase.

Not the best way to instill customer confidence.

ES6 does provide a way of handling complex templating by allowing you to write a function which sees and allows you to manipulate interpolated values as the template is being converted into a string.

The syntax takes some getting used to, but makes sense after some use:

var firstPurchaseAmount = 1000;
var secondPurchaseAmount = 19.95;

function templateParse(strings, ...values) {
  var i;
  console.log('Strings: ');
  for (i=0; i < strings.length; i += 1) {
    console.log(i + ' | ' + strings[i]);
  }  
  console.log('Values: ');
  for (i=0; i < values.length; i += 1) {
    console.log(i + ' | ' + values[i]);
  }  
}

var message = templateParse`Total purchases: ${firstPurchaseAmount + secondPurchaseAmount}
Thank you for your ${firstPurchaseAmount} and ${secondPurchaseAmount} purchases.`;

In this example above we have a templateParse function which accepts a strings array and then a values array. The three periods (otherwise known as the dot-dot-dot or lesser known ellipsis) acts here as the spread operator which we looked at earlier.

Using this method we're able to get at each fragment of the template and later manipulate those segments based on logic requirements.

Here's what we get when we run the code above:

Strings:
0 | Total purchases:
1 | Thank you for your
2 | and
3 | purchases.
Values:
0 | 1019.95
1 | 1000
2 | 19.95

Notice how strings and values made available.

Destructuring assignment

Destructuring assignment allows us to destructure an iterable or object into variables.

With ES5 we had to do this:

var arr = [1,2,3];
var a = arr[0];
var b = arr[1];
var c = arr[2];
console.log(a,b,c);

ES6 allows us to assign the valus of an array (iterable) to variables.

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

We can also do ths with objects:

var employee = {name: 'John Smith', role: 'CTO'};
var name = employee.name;
var role = employee.role;

console.log(name, role);
let employee = {name: 'John Smith', role: 'CTO'};
let name, role;

({name, role} = employee);
console.log(name, role);

You an even rename the variables:

let employee = {name: 'John Smith', role: 'CTO'};
let employeeName, employeeRole;

({name:employeeName, role:employeeRole} = employee);
console.log(employeeName, employeeRole);

Array enhancements

ES6 introduces many new members to the Array object. In this regard, ES6 embraces array features which have been part of other languages such as Ruby and Python. This also means that you'll be relying less on external packages such as underscore and lodash.

We won't cover all of the new enhancements here, however we will look at a few.

Array.from

Using Array.from() you can create a new array from an existing collection. The way in which this works is powerful - let's have a look:

let str = 'the quick brown fox jumped over the lazy brown dogs';
let vowels = 'aeiouy'; 
let newArray = Array.from(str, function(value) {
  if (vowels.includes(value)) {
    return value;
  }
});
console.log(newArray);

[null,null,"e",null,null,"u","i",null,null,null,null,null,"o",null,null,null,null,"o",null,null,null,"u",null,null,"e",null,null,"o",null,"e",null,null,null,null,"e",null,null,"a",null,"y",null,null,null,"o",null,null,null,null,"o",null,null]

Here we use array from to iterate the str string using a function which identifies vowels. The second parameter to the Array.from is a function which receives a single value at a time from a collection. In our case, our collection is a string of characters. Let's look at another example.

let names = [
  'James', 'Sam', 'Ryan', 'Alex', 'Albert', 'Larry', 'Mike'
];
let vowels = 'aeiouy';

var namesWithSingleVowel = Array.from(names, function(name) {
  let count = 0;
  Array.from(name, function(letter) {
    if (vowels.includes(letter)) {
      count += 1;
    }
  });
  if (count === 1) {
  	return name;
  }
});
console.log(namesWithSingleVowel);
[null,"Sam",null,"Alex","Albert",null,null]

Object literal enhancements

In ES5 we can create an employee object as follows:

var name = 'Shane Smith';
var position = 'Legal counsel';

var employee = {
  employeeName: name,
  employeePosition: position
};

console.log(JSON.stringify(employee));

ES6 offers a shorthand version where we don't have to enter the object labels:

var name = 'Shane Smith';
var department = 'Legal';

var employee = {
  name,
  department
};

console.log(JSON.stringify(employee));

The output becomes:

{"name":"Shane Smith","department":"Legal"}

We can also use this shorthand syntax with functions.

In ES5 we can declare functions this way:

var name = 'Shane Smith';
var department = 'Legal';
var phoneNumber = '555 555-5555';

var employee = {
  name,
  department,
  phoneNumber,
  getPhoneNumber: function() {
    return phoneNumber;
  }
};

console.log(employee.getPhoneNumber());

When using ES6 we can use a shorthand version which omits the colon character and function keyword:

var name = 'Shane Smith';
var department = 'Legal';
var phoneNumber = '555 555-5555';

var employee = {
  name,
  department,
  phoneNumber,
  getPhoneNumber() {
    return phoneNumber;
  }
};

console.log(employee.getPhoneNumber());

Where to go from here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment