The road to
ES Next.
By Mahdi Pedramrazi
April 2017
Mahdi Pedram
eBay Buyer Experience & Verticals
JavaScript Developer
Agenda
- History of JavaScript
- ES2015 Syntax & Examples
- Resources
- Q&A
History of JavaScript
Birth of Mocha by Brendan Eich
in 10 days
May 1995
Renamed to LiveScript
Sep 1995
Netscape Navigator 2.0 beta release
Renamed to JavaScript
Dec 1995
Netscape Navigator 2.0 beta 3 release
ECMAScript is standard specification to standardize JavaScript
ECMAScript published in the first edition of the ECMA-262 standard in June 1997.
ECMAScript
Second Edition
June 1998
Editorial changes
ECMAScript
Third Edition
December 1999
regular expressions
try/catch exception handling
ECMAScript
Forth Edition
Never Happened
Some features dropped.
Some feature proposed for Harmony release.
ECMAScript
Fifth Edition
Dec 2009
strict mode
JSON
reflection on object properties
ECMAScript
5.1 Edition
June 2011
revision of 5.0 that corrects some errors in the document
ECMAScript
6th Edition - ES2015
June 2015
new syntax
classes & modules
iterators & for-of loop
collections
promises
reflection & proxies
ECMAScript
ES 2016
June 2016
exponentiation operator (**) Array.prototype.includes.
ECMAScript
ES 2017
Stage 4
Async Functions
Shared memory and atomics
ES2015 Syntax
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
Block Scope Declaration
<ES2015 block scope variables wasn't supprted
Variables are function scoped
function person() {
var name = "john";
var age = 30;
console.log(str); // prints: undefined
if (age > 25) {
var str = "It's time to work harder";
console.log(str); // prints: "It's time to work harder"
}
console.log(str); // prints: "It's time to work harder"
}
Variable declaration gets Hoisted to the top.
function person() {
var name = "john";
var age = 30;
var str;
console.log(str); // prints: undefined
if (age > 25) {
str = "It's time to work harder";
console.log(str); // prints: "It's time to work harder"
}
console.log(str); // prints: "It's time to work harder"
}
hoisted to the top
Text
Hoisted variables are initialized with undefined
ES2015
Block Scope variables
let & const
Block Scoping with let
var name = "John";
{
let name = "Paul";
console.log(name); // prints: Paul
}
console.log(name); // prints: John
not initialized until they appear in the block
Temporal Dead Zone (TDZ)
{
console.log(a); // undefined
console.log(b); // Uncaught ReferenceError: b is not defined.
// `b` is declared but it's in TDZ.
if (typeof b === undefined) { // ReferenceError
//..
}
var a;
let b;
}
Accessing too early let references are called TDZ
Initially, storage space (binding) is created for the let variable but the variable remains uninitialized
Use let in for loops
for (let j=0; j < 5; j++){
setTimeout(function() {
console.log(j); // 0 1 2 3 4
}, 1000)
}
j is redeclared in every iteration.
Creates a new lexical scope in each iteration
for (var i=0; i < 5; i++){
setTimeout(function() {
console.log(i); // 5 5 5 5 5
}, 1000)
}
i is defined once, hoisted to the top of the function.
when setTimeout gets executed i === 5
Const Declaration
Creates a read only variable after the initial value is set.
- All const variables should be declared and initialized.
- "const" variables can't get reassigned.
Note: not restricted on the value but on variable assignment.
{
const name = "john";
console.log(name); // john
name = "alex"; // TypeError!
const arr = [1, 2, 3];
arr.push(4);
arr; // [1,2,3,4];
arr = 5; // TypeError.
const a; // Uncaught SyntaxError: Missing initializer in const declaration
}
Block-Scoped function
functions declared inside a block are block scoped.
var a = 1;
if (a === 1) {
function foo() {
console.log("1");
}
} else {
function foo() {
console.log("2");
}
}
foo() // <ES6 environment prints 2.
// ES6 throws ReferenceError
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
Spread/Rest Operator
Spread Operator
use ... behind an any iterable.
spread out to individual values
function numbers( a, b, c ) {
console.log(a, b, c); // 1 2 3
}
numbers(1, 2, 3);
numbers(...[1 ,2 ,3]);
expand value or spreading out in other context
var a = [2, 3, 4];
var b = [1, ...a, 5];
console.log(b); // [1, 2, 3, 4, 5];
Rest Operator
use ... gathers set of of values to combine values
function numbers( a, b, ...z ) {
console.log(a, b, z); //1 2 [3, 4, 5]
}
numbers(1, 2, 3, 4, 5);
No more arguments Object
...args gathers all parameters.
great replacement for arguments object
function numbers(...args) {
args.shift();
console.log(...args); // 2 3 4
}
numbers(1, 2, 3, 4);
function numbers() {
var args = Array.prototype.slice.call(arguments);
args.shift();
console.log.apply(null, args); // 2 3 4
}
numbers(1, 2, 3, 4);
pre ES6
Array-Like object
rest operator
spread operator
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
Default Parameter Values
Pre ES6
No Default Value
function foo(x, y) {
x = x || 10;
y = y || 20;
console.log( x + y);
}
foo(0, 6); // 16
Expected 6
0 is falsy
Default Parameter Values
function foo(x = 10, y = 20) {
console.log( x + y);
}
foo(null, 6); // 6 <-- null coerces to 0
foo(0, 6); // 6
foo(5, undefined) // 25 <-- undefined interprets as missing
foo(5, null); // 5 <-- null coerces to 0
ES6 version
undefined interprets as missing
null coerces to 0
Required Parameters
function required() {
throw new Error('Missing parameter');
}
function foo(mustBeProvided = required()) {
return mustBeProvided;
}
foo(); // Uncaught Error: Missing parameter
Example:
use default values for required parameters
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
Destructuring
Structured Assignment
function names() {
return ["John", "Alex", "Mike"];
}
var tmp = names(),
john = tmp[0],
alex = tmp[1],
mike = tmp[2];
manually assigning indexed values from an array
function values() {
return {
a: 1,
b: 2;
}
}
var tmp = values(),
a = tmp.a,
b = tmp.b;
manually assigning property values from an object
- manual or structured assignment needs extra variables
- lots of boilerplate code
Destructuring
- no need for additional temp variables.
- much cleaner
function names() {
return ["John", "Alex", "Mike"];
}
var [ john, alex, mike ] = names();
console.log(john, alex, mike); // John Alex Mike
array destructuring
function values() {
return {
a: 1,
b: 2;
}
}
var { a, b } = values();
console.log(a, b); // 1 2
object destructuring
Assignment not declaration
function values() {
return {
a: 1,
b: 2
}
}
var a, b;
({ a, b} = values());
[ c, d ] = [3, 4];
Destructuring is a general assignment operation not a declaration
wrap object destructuring in (...).
Objects: Variable Alias
- Data gets stored in variable alias or target.
- Source and target variables are the same, no need to change
function values() {
return {
a: 1,
b: 2;
}
}
var { a: firstNumber, b } = values();
console.log(firstNumber, b); // 1 2
console.log(a); // Reference Error
variable alias
{ a, b } // source and target are the same
{ a: a, b: b } // same as above - source and target are the same
variable alias
source
Mapping & Transformation
Any valid assignment expression is allowed
for both Array destructuring and Object destructuring.
// Object mapping and transformation
var obj = { a: 1, b: 2 };
var o = {};
({ a: o.x, b: o.y } = obj);
console.log(o.x, o.y) // 1 2
// Array transformation - reordering
var a1 = [ 1, 2, 3],
a2;
[ a2[2], a2[0], a2[1] ] = a1
console.log(a2); // [2, 3, 1]
//-----Mapping Object to Array--------
var obj = { a: 1, b: 2 };
var arr = [];
({ a: arr[0], b: arr[1] } = obj);
console.log(arr[0], arr[1]) // 1 2
//-----Mapping Array to Object--------
var a1 = [ 1, 2, 3],
o = {};
[ o.a, o.b, o.c] ] = a1;
console.log(o.a, o.b, o.c); // 1 2 3
Object/Array mapping and transformations
Map an Array to an Object or visa versa
No need to assign all values
var arr = [ 1, 2, 3];
var [ ,,c ] = arr
console.log(c); // 3;
var obj = { a: 2 };
var { b } = obj;
console.log(b); // undefined
use "," to skip an index
variable that is not defined will be assigned undefined
var arr1 = [2, 3, 4];
var [ b, ...c ] = arr1;
console.log(c) // [3, 4]
use rest operator ... for gather behaviour
Default Value Assignment
var [ a = 10, b = 4, c] = [undefined, 1, 2];
console.log(a, b, c); // 10 1 2
var { x, y, z = 10, k: KK = 20 } = { x: 1, y: 2, z: 3, k: undefined };
console.log(x, y, z, KK); // 1 2 3 20
Array:
Object:
Nested Destructuring
var [a, [b, c, d], e] = [ 1, [2, 3, 4], 5];
console.log( a, b, c, d, e); // 1 2 3 4 5
var App = {
model: {
Item: function() {}
}
};
var { model: { Item } } = App;
// instead of
var Item = App.model.Item;
destructure nested arrays
destructure object namespaces
Destructure Parameters
function numbers([x, y]) {
console.log(x, y);
}
numbers( [1, 2] ); //1 2
numbers( [1] ); // 1 undefined
numbers( [] ); // undefined undefined
numbers(); // uncaught Exception - TypeError
Default values replace undefined values
array destructuring for parameters
object destructuring for parameters
function numbers({x, y}) {
console.log(x, y);
}
numbers( { x :1, y: 2 ); //1 2
numbers( { x: 1 } ); // 1 undefined
numbers( {} ); // undefined undefined
numbers(); // uncaught Exception - TypeError
uncaught exception
Destructure Defults
function numbers([x, y = 5] = []) {
console.log(x, y);
}
numbers(); // undefined 5
array destructuring for parameters
default object properties overwrites destructured values.
function numbers({x = 1, y = 1} = { x: 3}) {
console.log(x, y);
}
numbers(); // 3 1
numbers({}); // 1 1
Assign default array or object when no parameter is passed.
Assign default values for destructured variables
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
Object Literal Extensions
Concise Properties
Properties that are the same name as lexical identifier can get shorten
var a = 1;
var b = 2;
var o = {
a: a,
b: b
};
a: a looks redundant
var a = 1;
var b = 2;
var o = {
a,
b
};
Concise Methods
new way: function shorthand
var o = {
a: function() { ... },
b: function() { ... }
};
old way
var o = {
a() { ... },
b() { ... }
};
Computed Property Names
var str = "string";
var o = {
["some string"]: 1,
["some " + str]() { ... }
};
any valid expression can appear inside the [...]
Object Super
var animal = {
eat() {
console.log("animal:eat");
}
};
var dog = {
eat() {
super.eat();
console.log("dog:eat");
}
};
Object.setPrototypeOf( dog, animal );
dog.eat(); // animal:eat
// dog:eat
Object.getPrototypeof(dog) // animal object
super is allowed only in consise methods.
super is locked statically to the prototype of dog
Concise Methods Gotcha
Concise method imply anonymous function expression.
not a good idea for recursion or event binding
function func(obj) { ... }
func({
someMethod() {
if(...) {
return someMethod(); //uncaught exception - ReferenceError
}
}
});
something: function() {} // anonymous function expression
something: function something() {} // named function expression
Inner function used for recursion
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
Arrow Functions
Arrow Functions
function example(a, b) {
a *= 2;
b *= 3;
return a + b;
}
var example = (a, b) => {
a *= 2;
b *= 3;
return a + b;
}
a regular function declaration
Arrow function
Arrow functions are always anonymous function expressions.
Arrow Functions guidelines
var f1 = (a, b) => {
a++;
b++;
return a + b;
};
var f3 = (x, y) => x + y;
No parameter always needs ( )
Single Parameter: no need for ( )
var f1 = x => x * 2;
2+ Parameter: requires ( )
More than one statement requires { ... }
var f1 = () => 5;
Arrow Functions Example
var a = [1, 2, 3];
var b = a.map(function(n) {
return n * 2;
});
console.log(b) // [2, 4, 6];
old style
var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b) // [2, 4, 6];
new style
Arrow Functions Advantages
1. Shorter Syntax
2. this has a lexical scope.
lexically inherits "this" from the surrounding scope
3. Does not bind this, arguments, super, or new.target.
Example
var controller = {
makeRequest: function(){
var self = this;
btn.addEventListener("click", function() {
self.makeRequest(...);
}
}
};
var controller = {
makeRequest: function(){
btn.addEventListener("click", () => {
this.makeRequest(...);
}
}
};
Lexical Scope
Dynamic Scope
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
for..of loop
loops over the set of values produced by an iterator
for..of loop
Arrays
Strings
Generators
Collections
Built-in Iterables
for..of loop
var arr = [1, 2, 3, 4];
for (let val of arr) {
console.log(val); // 1 2 3 4
}
var arr = [1, 2, 3, 4];
var val;
for (var i = 0; i < arr.length; i++) {
val = arr[i];
console.log(val); // 1 2 3 4
}
pre ES6
ES6
under the hood
var arr = [1, 2, 3, 4];
for (let val of arr) {
console.log(val); // 1 2 3 4
}
var a = [1, 2, 3, 4];
for (
let ret,
it = a[Symbol.iterator]();
( ret = it.next()) && !ret.done; )
{
console.log(ret.value); // 1 2 3 4
}
under the hood
ES6
ES2015 Syntax
- Block Scope Declaration
- Spread/Rest Operator
- Default Parameter Values
- Destructuring
- Object Literal Extensions
- Arrow Functions
- for..of loop
- Symbols & Iterators
Symbols & Iterators
Symbols
Note:
- Don't write new Symbol it's not a constructor
- use
typeof operator to identify
var symbol = Symbol("some description");
typeof symbol // "symbol"
new Symbol() // Uncaught TypeError: Symbol is not a constructor
- New primitive type
- value is hidden an unobtainable
- string-like value that can't collide with other values
Symbols
Note:
- if it finds in the registry it will return in
- if it doesn't find it creates a new one and return it.
- make sure to namespace your symbols
var EVT_LOGIN = Symbol("event.login");
evthub.listen( EVT_lOGIN, () => { ... });
Available in the function scope
var EVT_LOGIN = Symbol.for("event.login");
evthub.listen( EVT_lOGIN, () => { ... });
Global symbol registry: Symbol.for("...");
Symbols: accessing key
var s = Symbol.for("event.login");
var desc = Symbol.keyFor(s);
console.log( desc ); // event.login
use Symbol.keyFor() to extract the key
Symbol.iterator
var arr = [1, 2, 3];
var it = arr[Symbol.iterator]();
it.next(); // { value: 1, done: false }
it.next(); // { value: 2, done: false }
it.next(); // { value: 3, done: false }
it.next(); // { value: undefined, done: true }
array example
Symbol.iterator is a built in symbol
Collections
var m = new Map();
m.set( "key 1", 1 );
m.set( "key 2", 2);
var it = m.entries();
it.next(); // { value: ["key 1", 1], done: false }
var it = m[Symbol.iterator]();
it.next(); // { value: ["key 1", 1], done: false }
Map example
.entries() returns an iterator
Custom Iterators
var Fib = {
[Symbol.iterator]() {
var n1 = 1;
var n2 = 1;
return {
//make the iterator an iterable
[Symbol.iterator]() { return this; },
next() {
var current = n1;
[n1, n2] = [n2, n1 + n2];
if(current > 10 ) {
return { done: true}
}
return { value: current, done: false};
},
// will get called on break, continue, throw, return
return(v) {
return { value: v, done: true }
}
}
}
};
for (var v of Fib) {
console.log(v);
}
var iterator = Fib[Symbol.iterator]();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
What's Next
ECMAScript 2017.
Async functions
Shared memory and atomics
References
You Don't Know JS: ES6 & Beyond
by Kyle Simpson
Understanding ECMAScript 6: The Definitive Guide for JavaScript Developers
By Nicholas c Zakas
Overwhelmed with tools
Focus on Fundamentals
Thank You
Q&A
The road to ES Next.
By pedramphp
The road to ES Next.
History of JavaScript and ES2015 syntax
- 2,507