ES2015 Intro
Reference
January 29, 2018
I’ve been looking forward to this for a while! Although I’ve used ES6 in several projects and courses here and there, until now I haven’t really had a proper introduction to the basic ins & outs. This is the overview of all of the course sections on ES6 (aka ES2015).
For reference:
- const Keyword
- let Keyword
- Template Strings
- Arrow Functions
- Default Parameters
- For…of Loops
- Rest & Spread Operators
- Improvements For Working With Objects
- Improvements For Working With Arrays
- Improvements For Working With Strings
- Improvements For Working With Numbers
- Destructuring Objects & Arrays (& Swap)
- Class Keyword, and Methods
- Prototypal Inheritance - Extends & Super Keywords
- Maps & WeakMaps
- Sets & WeakSets
- Promises
- Generators
Const
The const
variable sets a value that cannot be changed for strings, numbers, booleans, null
, undefined
, or Symbol
. Note that arrays and objects can be changed:
var bim = "bim"; // bim |
Let
The let
variable sets a value with scope only in certain blocks (if, for, while, do, try, catch, finally). Let can be reassigned, but cannot be redefined after its initial declaration. One difference between var
and let
: although let
does hoist to the top of the block it’s in, it’s definition does not and trying to access it will result in a Reference Error:
function hello() { |
Let is useful when you want a variable to only be accessible in a specific scope. An example with setTimeout:
// As below, var is global and the for loop runs before setTimeout |
Template Strings
Template strings give a more streamlined way to concatenate strings:
// Old way: |
You can also write multi-line strings with backticks.
Arrow Functions
Functions can also be streamlined with arrow functions. And bonus: if the function is on one line, no curly braces or return
statement are needed:
// ES5 |
Another examples with more involved functions:
// ES5 |
Note that is there is only one argument in the function, it does not need to be wrapped in parentheses.
One really important thing about arrow functions is that unlike using the function
keyword, the keyword this
is not automatically attached to the function. Instead, this
is attached to the enclosing context. So be sure to use the function
keyword if this
is necessary:
var instructor = { |
For this reason, it’s bad form to use arrow functions as methods on an object!
Another important difference is how the arguments
keyword works. It doesn’t! Well, it doesn’t work inside a function, but it does work if it’s called inside a function that’s in another function.
Default Parameters
Super cool! You can set a default value for the parameters of a function with ES6. If you pass one argument to a function with two parameters, it will consider the argument as the first default). Examples:
function add(a=7, b=9) { |
For…of Loops
Works in places where for...in
loops can’t, like in arrays. Can’t be used on objects, or any other data type without the Symbol method in its prototype. Strings, arrays, maps, and sets do have this symbol iterator.
Rest & Spread Operators
Uses ...
as a placeholder for the rest
of the arguments in a function:
// ES5 |
When ...
is not used as arguments, it’s a spread operator and can be used to spread out all of the values in an array:
var arr1 = [1,2,3]; |
This can be useful with methods that can’t take an array as a parameter:
var arr = [3,2,4,1,5]; |
function sumValues(a,b,c){ |
Improvements For Working With Objects
There are several syntax changes which make it easier to work with objects using ES6:
Defining Objects:
var firstName = "Nia"; |
Adding Methods to Objects:
// ES5 |
Adding Properties to Objects:
// ES5 |
Object.Assign
In ES5 you can’t assign an object to another without changing the original object:
// ES5 |
To get around this reference issue, we can use the assign
method:
// ES2015 |
Object.assign()
accepts a series of objects and returns a new object with all of the keys and values assigned to it from the series. To create a new object, be sure to include an empty object as the first parameter. Otherwise it will alter the first parameter with all of the new key-value pairs added to it.
But do note: it doesn’t create a deep clone; if this is necessary it will need to be hard coded:
// ES2015 |
Improvements For Working With Arrays
Array.from()
Array.from()
allows us to create an actual array from an array-like object (as in from strings, maps, sets, ...arguments
, DOM selectors, etc.). These objects look like an array but don’t have all of the array methods attached:
// ES5 |
Find and FindIndex
Find is a useful way to search through an array for a value without using a for
loop. The find()
method accepts a callback with value, index and array (just like forEach, map, filter, etc.) and returns the value if found, or undefined
if not found.
var instructors = [{name: "Elie"}, {name: "Matt"}, {name: "Tim"}, {name: "Colt"}]; |
If you only need the index, rather than writing this function with two parameters and returning the index, there is another method findIndex
which just returns the index automatically, or -1
if the item is not found.
instructors.findIndex(function(val){ |
Improvements For Working With Strings
The includes
method is more straightforward than using indexOf
to look for a value in a string: it returns a boolean if the value is in the string or not. Note that as of ES2016 the includes()
method works on arrays as well as strings.
//ES5 |
Improvements For Working With Numbers
Now there is a simpler way to check if a number is not a number NaN
using the isFinite
method which is called on the Number
constructor:
// ES5 |
Similarly you can use Number.isInteger()
to check for an integer.
Destructuring Objects & Arrays (& Swap)
ES2015 makes it a bit easier to pull/reference values stored in objects and arrays.
Object Destructuring
Given an object:
var instructor = { |
To create variables from the values stored within the object, ES5 code is a bit repetitive:
var firstName = instructor.firstName; |
With ES2015 we can create the variables with one line of code by wrapping the keys inside curly braces. The variable names must match the key names.
var {firstName, lastName} = instructor; |
…BUT if we want to rename the variables to something other than the key names, this is possible:
var {firstName:first, lastName:last} = instructor; |
This also is useful for creating objects. Rather than writing a createObject
function with lots of or statements, we can pass a destructured object into the function as a parameter instead. This way the default will be invoked if nothing is passed to the function, otherwise it will create an object as desired:
// ES5 Way |
We can also pass a destructured object as a parameter to a function if we know the key names from the function:
// Given a known object... |
Array Destructuring
The setup is similar to working with objects: the variable names go into an array:
// Given an array... |
Variables can also be assigned to each result of a function when the output is an array:
// Given a function... |
Swapping
And a huge win!! A temp
variable is no longer needed to swap values, instead we can swap directly:
//ES5 |
This example from the class is a weird choice because couldn’t you just return [b, a]
from the ES5 function? But anyway, I’ve needed this before so not complaining!
Class Keyword, and Methods
The class
data structure is now available in JavaScript as a reserved keyword. The class
keyword creates a constant which cannot be redeclared, and it doesn’t hoist so classes should be declared at the top of a file. We can still use new
keyword to create objects, now called instances. Example:
// ES5: create a constructor function |
Instance Methods
Note that with class
the prototype is abstracted away, and instead, instance methods should be included in the class definition. Under the hood, the method is added to the prototype for you:
// ES5: methods are added to the prototype |
Class Methods, aka Static Methods
If you want to add a method to the class itself rather than to objects created from the class, we use the static
keyword. These are called static methods; some other examples are array.isArray
, Object.create
. To add static methods in ES6:
// ES5 Class Method definition |
Prototypal Inheritance - Extends & Super Keywords
We learned about prototypal inheritance in a previous section: this is how you assign methods from one constructor function to another in a way that will also more the this
reference to the new object. With ES2015 the new keyword extends
make this one step instead of two:
// ES5 Steps |
This is simplified in ES2015 with extends
, which brings over all of the methods from the first class onto the second. Combined with the super
keyword, this allows you to set up one class based on another, transfer the methods to the new class’ prototype, and still reduce code duplication without requiring the apply
method to do it:
class Person { |
Maps & WeakMaps
Map
is another new data structure to ES2015, and they are similar to “hash maps” in other languages. A Map is like an object, except that the keys can be any data type. A WeakMap
is similar to a Map, except that all of the keys must be objects and you can’t iterate over them. While WeakMap
s are less common, there are several reasons to use a Map
:
- Finding the size is easy - no more loops or Object.keys()
- You can accidentally overwrite keys on the Object.prototype in an object you make - maps do not have that issue
- Iterating over keys and values in a map is quite easy as well
- If you need to look up keys dynamically (they are not hard coded strings)
- If you need keys that are not strings!
- If you are frequently adding and removing key/value pairs
- If you are operating on multiple keys at a time
Maps are created with the new
keyword and key-value pairs are altered with set
and delete
. Unlike an object, you can also get the size()
of a Map:
var firstMap = new Map; |
To access the values in a map, the get()
method is used. Maps can also be iterated over with forEach
and for...of
loops:
firstMap.get(1); // 'Elie' |
There is also a built-in iterator for keys and values, or you can access everything together by destructuring an array and using the entries
method:
firstMap.values(); // MapIterator of values |
Sets & WeakSets
A Set
is another new data structure to ES2015; it’s an object in which all values must be unique. So sets are useful when you want to ignore duplicate values, don’t need to access values with keys, or don’t care about the ordering of the values. A WeakSet
is similar to a set, except that all of the values must be objects, and they cannot be iterated over.
Sets are also created with the new
keyword; they are altered with the add
and delete
methods. You can also check if a set contains a value with has
:
var s = new Set; |
Sets can be iterated over with a for...of
loop:
s2[Symbol.iterator]; // function(){}... |
Promises
Promises help run asynchronous code: it’s a promise to return some result one the code has finished running. Promises are created with the new
keyword and accept a callback function with 2 parameters: resolve and reject (although you can name it whatever). Each parameter itself is a function which will be run depending on the outcome of the promise. To create an async function:
function displayAtRandomTime(){ |
At call time, the success or failure (aka resolve
or reject
) functions are called by .then()
or .catch()
depending on the result:
displayAtRandomTime().then(function(value){ |
Promise.all()
Promises can be chained with multiple .then()
functions (aka, a really dumb name, they are thenable), each of which returns a value to the next. When there are multiple promises to be resolved, we can use the Promise.all()
method, which accepts an array of promises. This will reject all of the promises once a since promise in the chain is rejected. If it’s going to fail, it should fail quickly!
Likewise, if all of the promises will resolve, it returns an array of the returned values from all of the promises in the order in which they were resolved (even if they are not resolved sequentially…they may not be).
// We write a function that returns a promise via jQuery |
Generators
Generators are a new type of function available in ES2015. Normal functions will keep running until something is returned, or there is no more code to run. But with generator functions, execution can be paused and resumed later. This is helpful when there is a time-consuming function and you only need to run parts of it at a time (if you ask me, write smaller modular functions?).
A generator function is created with the star *
symbol. When a generator function is invoked, the object it returns has a method next()
, and that method
returns another object, which has the keys value
and done
:
value
is what is returned from the paused function using theyield
keyworddone
is a boolean which returnstrue
when the function has completed
function* pauseAndReturnValues(num){ |
We can place multiple yield
keywords inside of a generator function to pause multiple times:
function* printValues(){ |
Generator functions have a Symbol property so can be iterated over with a for...of
loop:
function* pauseAndReturnValues(num){ |
Generators can also be used with asynchronous methods to pause for a promise:
function* getMovieData(movieName){ |
But note!: This is improved even further in ES2017 with async
functions, so newer practices are available. As a result generators are less & less common.
Other Stuff
Next lessons we do ES2016 and ES2017 so this document will get even bigger!!!!!