ECMAScript 2015

aka JavaScript ES6

Topics

  1. String Template Literals
  2. let and const
  3. Default Parameters
  4. Arrow Functions
  5. Rest / Spread Operator
  6. Array and Object destructuring
  7. Array.from()

String

Template

Literals

Template Literals Syntax

You can now declare strings with `back ticks` (grave accent). These are special strings that allow for interpolation that is a lot cleaner that old-school string concatenation.

var firstName = "Jìan";
var lastName = "Yáng";
var title = "web developer";

// ughhh, so much concatenation...
var old = "Hi, my name is " + firstName + " " + lastName + ", and I am a " + title + ".";

// much better
var new = `Hi, my name is ${firstName} ${lastName}, and I am an ${title}.`;

You can interpolate full JavaScript expressions

Once you're in the ${ } block, you're back in regular JavaScript, and any expression you put in gets evaluated.

function addTwo(x, y) {
   return x + y;
}

var j = 99;
var k = 42;

var numberyString = `Adding ${j} and ${k} together results in ${addTwo(j, k)}.`;

What does interpolating do

under the hood?

Essentially anything in the ${ } will be given the .toString() treatment, so be careful with interpolating objects.

var character = { name: 'Thor', age: 1000 };

var str = `Favorite Character: ${character}`;

// 'Favorite Character: [object Object]'


// Much better if we use JSON.stringify

str = `Favorite Character: ${JSON.stringify(character)}`;

// 'Favorite Character: {"name":"Thor","age":1000}'

let

and

const

const

The const keyword lets you prevent a variable from ever being re-declared or re-assigned.

const PI = 3.14;

/* 

   bunch of code here 

*/


PI = 15;
// TypeError: Assignment to constant variable.
let

The let keyword creates a block-scoped variable.

for (var i = 1; i < 4; i++) {
   console.log(i);
}

// 1
// 2
// 3

console.log(i);
// 4
for (let i = 1; i < 4; i++) {
   console.log(i);
}

// 1
// 2
// 3

console.log(i);
// ReferenceError: i is not defined

It can be re-assigned but not re-declared (unlike var).

let z = 5;
z = 25;
let z = 10;
// SyntaxError: Identifier 'z' has already been declared

Block Scope

What is a code block?

{
   // this is a code block

   let x = 5;

   var y = 10;

   const z = -Infinity;
}

console.log(x);
// ReferenceError: x is not defined

console.log(y); 
// 10

console.log(z);
// ReferenceError: z is not defined

Essentially any pair of curly braces (outside of object syntax).

Surprise!

const is also block-scoped

Block Scope

You'll mostly use code blocks in for loops and if statements.

if (x > 10) {

  let happy = true; 
  // happy lives in this code block forever

}

console.log(happy);
// JavaScript's like: "never heard of 'em"

They're still there even if you omit the curlies

if (x > 10) let happy = false;

console.log(happy); // "JavaScript: 'who??'

Comparison of variable declaration keywords

Keyword Can Be Re-Assigned Can Be Re-Declared Scope Rules
var yes yes default (function scope only)
let yes no block scope
const no no block scope

Default

Parameters

Default Parameters for Functions

If you have parameters that might be undefined (i.e. the user didn't pass them), you can easily assign default values in ES6

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

console.log(multiply(5, 2));
// 10

console.log(multiply(5));
// 5

Note: these only work for undefined values, not other falsy values.

Arrow

Functions

=>

Arrow Functions are shorthand for Anonymous Functions

[1,2,3].forEach(function(el, idx) {
   console.log(el, idx);
});

/* is the same as */

[1,2,3].forEach((el, idx) => {
  console.log(el, idx);
});

They cannot be named functions and they only work as function expressions. Ideal for shortening callbacks.

Another Example

[1,2,3,4,5].filter(function(el, idx) {
   return el % 2 === 0;
});

/* is the same as */

[1,2,3,4,5].filter((el) => {
  return el % 2 === 0;
});

Arrow Functions have an implicit return if you leave out the curly braces





/* square everything */

const arr = [1,2,3];

const arrSquared = arr.map(el => el ** 2);

// [1, 4, 9]

Just 1 argument?

Param parentheses are optional

Arrow Functions do not

have their own this

const myArrowFunc = () => {
  console.log(this);
  // window! Inherited lexically
};

Unlike normal functions declared with the function keyword, arrow functions have no this context. Instead their this follows lexical scoping rules.

Arrow Functions Summary

  • Can only be used as shorthand for anonymous function expressions
  • Must put parentheses around parameters if there are 0 or 2+ parameters
  • Return statement is implied if you leave out curly braces
  • They do not make their own this; they inherit it lexically

Rest / Spread

Operator

Rest Parameters

function sumMany(...nums) {
  return nums.reduce((a, b) => a + b, 0);
}

sumMany(5, 10);  // 15

sumMany(10, 10, 10, 10, 10, 10, 10, 10, 10);  // 90

sumMany(1);  // 1

aka the coolest feature of ES6

In any function declaration, the ...nums collects any number of additional arguments you pass to a function into a single nums array.

Rest Parameters

function oneOrMoreArguments(first, ...more) {
  console.log(first);
  more.forEach(arg => {
    console.log(arg);
  });
}

You can also define a couple of params and collect the rest

In this instance, first is always going to be there while more will be an array of everything else you passed in.

Spread Operator

function takesFour(one, two, three, four) {
  console.log(one);
  console.log(two);
  console.log(three);
  console.log(four);
}

const names = ['Elie', 'Matt', 'Michael', 'Joel'];

takesFour(...names);
// Elie
// Matt
// Michael
// Joel

The same '...' syntax can also be used in a different context as the spread operator. When calling a function for instance, you can spread out array elements:

Spread Operator

const whiskey = {
  name: 'Whiskey',
  species: 'canine',
  cool: true
};

const anotherDog = { ...whiskey, name: 'Gandalf' };

/*

{
   name: 'Gandalf',
   species: 'canine',
   cool: true
}

*/

Or if you need to copy over pieces of an object!

'name' has to come after ...whiskey here. Why?

Object

and

Array

Destructuring

Object Destructuring

But that's like waaay too much typing / boring and redundant

let userData = { 
  username: 'hueter',
  id: 12345,
  password: 'fiddlesticks',
  firstName: 'Michael',
  lastName: 'Hueter',
  age: 'guess',
  isLegit: undefined
};

let username = userData.username;
let firstName = userData.firstName;
let lastName = userData.lastName;
let id = userData.id;
  

JavaScript programmers take things out of objects all the time.

Object Destructuring

So we came up with some syntactic sugar.

let userData = { 
  username: 'hueter',
  id: 12345,
  password: 'fiddlesticks',
  firstName: 'Michael',
  lastName: 'Hueter',
  age: 'guess',
  isLegit: undefined
};

let { username, firstName, lastName, id } = userData;

console.log(username);  // hueter
console.log(id);  // 12345

Object Destructuring

You can also rename things

const userData = { 
  username: 'hueter',
  id: 12345,
  password: 'fiddlesticks',
  firstName: 'Michael',
  lastName: 'Hueter',
  age: 'guess',
  isLegit: undefined
};

const { username: newName } = userData;

console.log(newName);  // hueter

Spread + Object Destructuring

const userData = { 
  username: 'hueter',
  id: 12345,
  password: 'fiddlesticks',
  firstName: 'Michael',
  lastName: 'Hueter',
  age: 'guess',
  isLegit: undefined
};

const { password, ...user } = userData;

console.log(user); 
/*
{ 
  username: 'hueter',
  id: 12345,
  firstName: 'Michael',
  lastName: 'Hueter',
  age: 'guess',
  isLegit: undefined
}
*/

Spread + Array Destructuring

You can apply the same concept to arrays!

const myFavoriteThings = ['teaching', 'music', 'hiking', 'dank memes'];

const [first, second, ...others] = myFavoriteThings;

console.log(first);  // 'teaching'
console.log(second);  // 'music'
console.log(others); //   ['hiking', 'dank memes']
Array.from()

Sometimes JavaScript gives you array-like objects that you wish were arrays

const paragraphsNodeList = document.querySelectorAll('p');
Array.isArray(paragraphsNodeList);  // false

const paragraphs = Array.from(paragraphsNodeList);
Array.isArray(paragraphs);  // true

Now you can easily make an Array out of those things with Array.from!

Array.from() under the hood

const cat = 'cat';

Array.from(cat);

// ['c', 'a', 't']

Basically it works by looking for anything with a .length property. Then it iterates over the items and pushes them into an array.

You can use this trick to build empty arrays of a certain size:

Array.from({ length: 5 });
// [undefined, undefined, undefined, undefined, undefined]

ES2015

By Michael Hueter

ES2015

JavaScript ES2015 (aka ES6) key features explained

  • 877