ES2015
Part One
Objectives
-
Understand what ES2015 is and how the term came to be
-
Refactor code to use let and const and explain the implications of using both
- Use template strings to avoid string concatenation in your JavaScript code
- Use arrow functions to write shorter functions and compare arrow functions and the function keyword
- Use ES2015 object enhancements to refactor code
- Explain what ES2015 default parameters are and how to use them
- Compare and contrast the rest and spread operators
- Unpack values from arrays and objects using destructuring
But first....
a little history
JavaScript Timeline
1995 + 1996
1997
1998
1999
2009
2015
2016
2017
Start
ES1
ES2
ES3
ES5
ES6 / ES2015
ES
2016
ES
2017
ES2015 Additions
- let, const
- template strings
- arrow functions
- default parameters
- rest and spread operators
- for...of loops
- object shorthand notation
- computed property names
- object destructuring
- array destructuring
- class keyword
- super and extends keywords
- Maps / Sets
- Promises
- Generators
- Object, Number, Array methods
const
var firstInstructor = "Colt";
firstInstructor = "Elie"; // no problem here
Can NEVER redeclare
const anotherInstructor = "Tim";
anotherInstructor = "Elie"; // TypeError
const anotherInstructor = "Elie"; // SyntaxError
Gotcha with const
const numbers = [1,2,3,4];
numbers.push(10); // 5
numbers; // [1,2,3,4,5]
numbers = "no!"; // TypeError
Can mutate if it is an object, but not declare again
let
let anotherInstructor = "Tim";
anotherInstructor = "Elie"; // no problems here!
let anotherInstructor = "Tim"; // SyntaxError
Can reassign, can not redeclare
Scope with let
var instructor = "Elie";
if(instructor === "Elie"){
let funFact = "Plays the cello";
}
funFact; // ReferenceError!
blocks create scope!
Hoisting with let
function helloInstructor(){
return elie;
var elie = "ME!";
}
helloInstructor(); // undefined
let does hoist, but we can not access the value - it is in a TDZ (Temporal Dead Zone)
function helloSecondInstructor(){
return colt;
let colt = "HIM!";
}
helloSecondInstructor(); // ReferenceError
Use Cases for let
for(var i = 0; i < 5; i++){
setTimeout(function(){
console.log(i);
},1000)
}
// 5 (five times)
for(var i = 0; i < 5; i++){
(function(j){
setTimeout(function(){
console.log(j);
},1000);
})(i)
}
// 0
// 1
// 2
// 3
// 4
Refactoring with let
for(let i = 0; i < 5; i++){
setTimeout(function(){
console.log(i);
},1000);
}
// 0
// 1
// 2
// 3
// 4
YOUR
TURN
Template Strings
var firstName = "Elie";
var lastName = "Schoppik";
console.log("Hello " + firstName + " " + lastName); // error prone!
Make sure you use backticks!
console.log(`Hello ${firstName} ${lastName}`); // Much nicer!
"
Hello
" // does not work!
`
Hello
How
Nice
Is
This!
` // works well!
Multiline Strings
// ES5
var add = function(a,b){
return a+b;
}
Arrow Functions
// ES2015
var add = (a,b) => {
return a+b;
}
Replace the keyword 'function' with =>
Just the start...
One-line arrow functions
var add = (a,b) => {
return a+b;
}
- You can put arrow functions on one line.
- But you must omit the return keyword as well as curly braces
We can go from:
var add = (a,b) => a+b;
To:
Refactoring with arrow functions
// ES5
[1,2,3].map(function(value){
return value * 2;
}); // [2,4,6]
// ES2015
[1,2,3].map(value => value * 2); // [2,4,6];
We can go from:
To:
Let's do it again!
function doubleAndFilter(arr){
return arr.map(function(value){
return value * 2;
}).filter(function(value){
return value % 3 === 0;
})
};
doubleAndFilter([5,10,15,20]); // [30]
var doubleAndFilter = arr => arr.map(val => val * 2).filter(num => num % 3 === 0);
doubleAndFilter([5,10,15,20]); // [30]
Notice that if we only have one parameter, we do not need parenthesis around it with arrow functions!
We can go from:
To:
So...what's the catch?
- Arrow functions are not exactly the same as regular functions!
- Arrow functions do not get their own 'this' keyword
- Inside of an arrow function, the keyword this has its original meaning from the enclosing context.
- The fact that arrow functions do not have their own this keyword can be quite helpful - you just need to understand when you might NOT want that!
var instructor = {
firstName: "Elie",
sayHi: function(){
setTimeout(function(){
console.log("Hello " + this.firstName);
}, 1000);
}
}
A familiar situation...
var instructor = {
firstName: "Elie",
sayHi: function(){
setTimeout(function(){
console.log("Hello " + this.firstName);
}.bind(this), 1000);
}
}
instructor.sayHi(); // "Hello undefined"
instructor.sayHi(); // "Hello Elie"
var instructor = {
firstName: "Elie",
sayHi: function(){
setTimeout(() => {
console.log("Hello " + this.firstName);
}, 1000);
}
}
instructor.sayHi(); // "Hello Elie"
Arrow functions as an alternative
Arrow functions do not have their own keyword this. The keyword this refers to its enclosing context (the instructor object).
But why does this work?
var instructor = {
firstName: "Elie",
// why can't we use an arrow function here?
sayHi: function(){
setTimeout(() => {
console.log("Hello " + this.firstName);
}, 1000);
}
}
instructor.sayHi(); // "Hello Elie"
One quick gotcha
If we use an arrow function, the sayHi function will not have its own keyword this - and the keyword this will not refer to the instructor object anymore!
We used both the function keyword and an arrow function - why?
var add = (a,b) => {
return arguments;
}
add(2,4); // ReferenceError: arguments is not defined
Arrow Functions and `arguments`
arrow functions do not get their own keyword arguments
One more note about 'arguments'
An arguments keyword can be accessed if the arrow function is inside of another function (it will be the outer functions arguments)
function outer() {
return innerFunction = () => {
return arguments;
}
}
outer(1)(2); // only prints out [1]
If you REALLY need the arguments to an arrow function, use the rest operator - we'll see that very soon!
var instructor = {
firstName: "Elie",
sayHi: () => `Hello ${this.firstName}`;
}
instructor.sayHi(); // "Hello undefined"
When NOT to use Arrow Functions
Arrow functions should NEVER be used as methods in objects since we will get the incorrect value of the keyword this. ES2015 provides a better alternative - we'll see it soon!
YOUR
TURN
function add(a, b){
return a+b;
}
add(); // NaN because a is undefined and b is undefined
Default Parameters
function add(a=10, b=20){
return a+b;
}
add(); // 30
add(20); // 40
var arr = [1,2,3,4,5];
for(let val of arr){
console.log(val);
}
// 1
// 2
// 3
// 4
// 5
For...of
- Can't access an index
- Can only be used on data structures with a Symbol.iterator method implemented (no objects!)
function printRest(a,b,...c){
console.log(a);
console.log(b);
console.log(c);
}
printRest(1,2,3,4,5);
// 1
// 2
// [3,4,5]
Rest
- The rest operator always returns an array
- Is called the rest operator "only" when it is a parameter to a function
- Is accessed without the ... in a function
- A better alternative to using the arguments array-like- object
// ES5
function sumArguments(){
var total = 0;
for(var i = 0; i < arguments.length; i++){
total += arguments[i];
}
return total;
}
Rest Continued
// ES2015
var sumArguments = (...args) => args.reduce((acc, next) => acc + next);
// A little fancier ES5
function sumArguments(){
var argumentsArray = [].slice.call(arguments);
return argumentsArray.reduce(function(accumulator,nextValue){
return accumulator + nextValue;
});
}
Spread
// ES5
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var arr3 = [7,8,9];
var combined = arr1.concat(arr2).concat(arr3);
- Used on arrays to spread each value out (as a comma separated value)
- Useful when you have an array, but what you are working with expects comma separated values
// ES2015
var combined = [...arr1, ...arr2, ...arr3];
// ES2015
Math.max(...arr); // 5
Spread instead of apply
var arr = [3,2,4,1,5];
Math.max(arr); // NaN
// ES5
Math.max.apply(this, arr); // 5
One more time
function sumValues(a,b,c){
return a+b+c;
}
var nums = [12,15,20];
// ES2015
sumValues(...nums); // 47
// ES5
sumValues.apply(this, nums); // 47
var firstName = "Elie";
var lastName = "Schoppik";
// ES5
var instructor = {
firstName: firstName,
lastName: lastName
}
Object Shorthand Notation
var firstName = "Elie";
var lastName = "Schoppik";
// ES2015
var instructor = {
firstName,
lastName
}
// ES5
var instructor = {
sayHello: function(){
return "Hello!";
}
}
Object Methods
// ES2015 - do NOT use arrow functions here!
var instructor = {
sayHello(){
return "Hello!";
}
}
// ES5
var firstName = "Elie";
var instructor = {};
instructor[firstName] = "That's me!";
instructor.Elie; // "That's me!"
Computed Property Names
// ES2015
var firstName = "Elie";
var instructor = {
[firstName]: "That's me!"
}
instructor.Elie; // "That's me!"
YOUR
TURN
Extracting values from data stored in objects and arrays
Destructuring
ES5
var instructor = {
firstName: "Elie",
lastName: "Schoppik"
}
var firstName = instructor.firstName;
var lastName = instructor.lastName;
firstName; // "Elie"
lastName; // "Schoppik"
Object Destructuring
var instructor = {
firstName: "Elie",
lastName: "Schoppik"
}
var {firstName, lastName} = instructor;
firstName; // "Elie"
lastName; // "Schoppik"
Different Variables
var instructor = {
firstName: "Elie",
lastName: "Schoppik"
}
var {firstName:first, lastName:last} = instructor;
first; // "Elie"
last; // "Schoppik"
function createInstructor(options){
var options = options || {};
var name = options.name || {first: "Matt", last:"Lane"}
var isHilarious = options.isHilarious || false;
return [name.first, name.last, isHilarious];
}
ES5 Default Values with an object
Lots of work!
createInstructor(); // ["Matt", "Lane", false]
createInstructor({isHilarious:true}); // ["Matt", "Lane", true]
createInstructor({name: {first:"Tim", last:"Garcia"}}); // ["Tim", "Garcia", false]
function createInstructor({name = {first:"Matt", last:"Lane"}, isHilarious=false } = {}){
return [name.first, name.last, isHilarious];
}
ES2015 Destructuring
- We're passing in a destructured object as a default parameter!
- We assign as a default value an empty object so ES2015 knows we are destructuring
- If nothing is passed in, we default to the destructured object as the parameter.
createInstructor(); // ["Matt", "Lane", false]
createInstructor({isHilarious:true}); // ["Matt", "Lane", true]
createInstructor({name: {first:"Tim", last:"Garcia"}}); // ["Tim", "Garcia", false]
Object fields as parameters ES5
var instructor = {
name: "Elie",
favColor: "Purple"
};
displayInfo(instructor); // ["Elie", "Purple"]
function displayInfo(obj) {
return [obj.name, obj.favColor];
}
Object fields as parameters ES2015
function displayInfo({name,favColor}) {
return [name, favColor];
}
Very common in React!
var instructor = {
name: "Elie",
favColor: "Purple"
};
displayInfo(instructor); // ["Elie", "Purple"]
Array
Destructuring
var arr = [1,2,3];
var a = arr[0];
var b = arr[1];
var c = arr[2];
a; // 1
b; // 2
c; // 3
ES5 vs ES2015
var arr = [1,2,3];
var [a,b,c] = arr;
a; // 1
b; // 2
c; // 3
ES5 vs ES2015
function returnNumbers(a,b) {
return [a,b];
}
[first, second] = returnNumbers(5,10);
first; // 5
second; // 10
function returnNumbers(a,b) {
return [a,b];
}
var first = returnNumbers(5,10)[0];
var second = returnNumbers(5,10)[1];
first; // 5
second; // 10
//ES5
function swap(a,b){
var temp = a;
a = b;
b = temp;
return [a,b];
}
swap(10,5); // [5,10]
Swapping Values
// ES2015
function swap(a,b){
return [a,b] = [b,a];
}
swap(10,5); // [5,10]
YOUR
TURN
Recap
- ES2015 gives us two new keywords for declaring variables let, const. Const ensures we can not redeclare a variable and let gives us block scope
- Easily evaluate variables in strings and create multi-line strings with ES2015 template strings. Don't forget the backticks!
- Create more concise functions using the => syntax, but these functions do not get their own this and arguments keywords
- Gather arguments to a function as an array using the rest operator and spread out values in an array to another value or function using ...
- Write more concise methods and property names using shorthand notation and computed property names
- Object destructuring is very useful for reducing duplication and passing in default parameters as a destructured object
- Array destructuring can also be used for swapping variables in an array without a separate swap function
ES2015 Part 1
By Elie Schoppik
ES2015 Part 1
ES2015 Introduction
- 3,396