ES6 of the Week

What is ES6 Anyway?
- ECMAScript 6, also known as ECMAScript 2015, is the (kind of) latest version of the ECMAScript standard. ES6 is a significant update to the language, and the first update to the language since ES5 was standardized in 2009.
ECMAScript? Aren't we learning JavaScript?
- ECMAScript is a language specification that JavaScript follows (as do other languages like JScript, ActionScript, and more).
A Brief History of Javascript
- 1995 - Netscape (Brendan Eich) releases LiveScript
- 1996 - Netscape submits it ECMA International for standardization
- 1999 - ECMAScript 3 (baseline for modern day JavaScript)
- 2009 - ECMAScript 5 (ES5)
- 2015 - ECMAScript 6 (ES6)!
Sparknotes version
-
ECMAScript: The official language name, refers to the standard.
-
JavaScript: Commonly used name for implementations of ECMAScript standard. Not tied to any version.
-
ECMAScript 5 (ES5): 5th edition of ECMAScript, what you're used to writing now.
-
ECMAScript 6 (ES6)/ ECMAScript 2015: 6th edition of ECMAScript, what we're going to be learning.
This Week's Episode:
const and let
arrow functions
Block scope vs. Function scope
- Remember that, in Javascript, var declares a function-scoped variable.
-
Const and let set a tighter scoping - "block" scoping
- Rather than being hoisted to the top of a function's scope, variables declared with const and let are hoisted only to the top of the code block
- For, if, while, try/catch all create code blocks

Hoisting
function fooWithVar (bar) {
if (bar) {
var baz = 'baz';
}
console.log(baz);
}
// to the JavaScript interpreter:
function fooWithVar (bar) {
var baz;
if (bar) {
baz = bar;
}
console.log(baz);
}
fooWithVar('hello world') // hello world
fooWithVar() // undefined
Blocked Out
function fooWithLet (bar) {
if (bar) {
let baz = 'baz';
}
console.log(baz);
}
// to the JavaScript interpreter:
function fooWithLet (bar) {
if (bar) {
let baz;
baz = bar;
}
console.log(baz);
}
fooWithLet();
// ReferenceError: baz is not defined
/** What's easier to debug: undefined,
or a ReferenceError? */
Const
- Declares a read-only reference to a value - all this means is that variables declared with "const" cannot be reassigned
- Note that you can still modify the assigned content of the variable (ex. if you assign the variable to an object, you can still modify the object - you just can't assign that variable to something else, like another object)
- Does not make the variable immutable!
- You must assign a value to a const-declared variable when you create it. You can't create it first and assign it later.
Const Comment
'use strict';
const foo = [];
const bar = {};
const baz = 1;
const quux = 'hello';
foo.push(bar); // okay
bar.someMethod = function () {} // also okay
baz = 2 // TypeError: Assignment to constant variable
quux += ' world' // TypeError: Assignment to constant variable
"Letting" you in on a cool secret
// remember me?
function createFunctions(n) {
let functions = [];
/* because using "let" to declare the variable "i" makes it block-scoped,
you don't have to worry about it being closed over */
for (let i = 0; i < n; i++) {
functions.push(function () {
return i;
});
}
return functions;
}
let myFunctions = createFunctions(5);
myFunctions[0]() // => 0 I work the way you thought I would!
myFunctions[1]() // => 1 Pretty cool, right?
Cleaning up
// the combination of let and arbitrary code blocks can help you free up memory faster
function suchCalculation () {
/* very function */
}
/* Arbitrary code blocks are also new with ES6
They prevent scope pollution - no need for a messy IIFE!
*/
{
let muchData = { /* large dataset */ }
suchCalculation(muchData);
}
/* At this point, the garbage collector will have cleaned up the large data set we used,
since we're outside the code block
*/
console.log('wow!');
Why Use Let and Const?
- More descriptive way to declare your data
- Protects your for loops from unwanted closure
Why Continue using Var?
- Maybe browser compatibility, if you're in an environment where you can't use Babel
- For the most part...you can replace var with const and let entirely; the Airbnb javascript style guide actually recommends doing just that!
Pt. 2
Arrow functions
"This"
Remember that, within a function, this is defined based on the execution context of a function
- If a function is executed as a method on an object, this will refer to the object itself, so that you can intuitively access other properties/methods on the object
What if I told you...
// say we have an object called Neo...
const Neo = {};
// and we also have a function
const bendSpoon = function () {
console.log(this.spoon);
};
// let's give our object a property and a method
Neo.spoon = 'spoon';
Neo.bendSpoon = bendSpoon;
// the execution context of bendSpoon is Neo, so this refers to Neo
Neo.bendSpoon(); // spoon
// the execution context of bendSpoon is the global context - there is no spoon
bendSpoon(); // undefined
Mr. Anderson...
const Neo = {};
const agentSmiths = ['Smith1', 'Smith2', 'Smith3'];
Neo.kick = function (agent) {
console.log('Neo kicked ', agent);
};
Neo.kickAgentSmiths = function () {
agentSmiths.forEach(function (agent) {
this.kick(agent);
});
};
Neo.kickAgentSmiths(); // TypeError: this.kick is not a function
// How can we help Neo?
Arrow functions
- A more concise way to write function expressions
-
Reminder:
- var fn = function () {} === function expression
- function fn () {} === function declaration
-
Reminder:
- The big difference: the body of arrow functions do not get their own dynamic this value. Instead, arrow functions have lexical this: their this context is the enclosing context
- This solves some issues you may have experienced with callback functions in methods like Array.prototype.forEach
Syntax
/* In a single-line arrow function, curly braces are optional,
and the function implicitly returns the value of the last expression.
You can include a return statement if you'd like, but it's optional.
This is called the 'concise body'
*/
arr.map(i => i * 2);
// If you have multiple arguments, they must go in parentheses
arr.reduce((prev, next) => prev + next);
// If you have no arguments, you can just use an empty ()
let foo = () => console.log('bar');
/* If you need more than one line, then you must use brackets
and must include the return statement
This is called the 'block body'
*/
let baz = (x) => {
if (x > 1) return x;
else return 1;
}
Using Arrow Functions
const Neo = {};
const agentSmiths = ['Smith1', 'Smith2', 'Smith3'];
Neo.kick = function (agent) {
console.log('Neo kicked ', agent);
};
Neo.kickAgentSmiths = function () {
agentSmiths.forEach(agent => this.kick(agent));
};
Neo.kickAgentSmiths();
/*
Neo kicked Smith1
Neo kicked Smith2
Neo kicked Smith3
*/
Arrow Combos
/*
Arrow functions love promise chains and array methods
*/
// Greatest http request of all time
$http.get('/api/artists')
.then(res => res.data)
.then(artists => artists.filter(artist => artist.name !== 'Kanye')
.catch(err => console.error);
Don't overdo it
const Neo = {};
const agentSmiths = ['Smith1', 'Smith2', 'Smith3'];
Neo.kick = function (agent) {
console.log('Neo kicked ', agent);
};
// now the kickAgentSmith function's this is no longer Neo
Neo.kickAgentSmiths = () => {
agentSmiths.forEach(agent => this.kick(agent));
};
Neo.kickAgentSmiths(); // TypeError: the Matrix has you
Other Arrow Function Facts
- The methods call(), apply(), and bind() will not change the value of this in arrow functions.
- There is no arguments object exposed by arrow functions - if you try to use arguments, it will just try to find an 'arguments' variable in the enclosing scope
- If you want to use concise body to return an object literal, you need to wrap it in parentheses - otherwise, it looks like you're trying to use block body!
- You can’t use arrow functions with the new keyword, attempting to do results in an error being thrown.
More Pointers
// Call and apply don't affect 'this'
let sum = (a, b) => a + b;
sum.call(null, 1, 2) // 3
sum.apply(null, [1, 2]) // 3
// On that note, don't expect 'arguments' to work
let differenceA = (a, b) => arguments[0] - arguments[1]; // nope
differenceA(2, 1) // TypeError
// See what's happening here?
let returnAnObject = () => { a: 1 };
let obj = returnAnObject();
obj.a; // TypeError: Cannot read property 'a' of undefined
let returnAnObjectForReals = () => ({ a: 1 });
let obj = returnAnObjectForReals();
obj.a; // 1
Why Use Arrow Functions?
- They look rad and can help turn your shorter functions into clean one-liners
- Intuitive this context eliminates the need to use self = this in some callbacks
When to be careful
- Whenever this is involved - make sure you know what kind of behavior you're getting
ES6 of the Week - 1 (const and let; arrow funcs)
By beelai88
ES6 of the Week - 1 (const and let; arrow funcs)
Const & Let / Arrow Functions
- 621