Created by Miguel Cobá / @MiguelCobaMtz
Arrows
Classes
Modules
Enhanced Object Literal
Template Strings
Destructuring
Default + Rest + Spread
Let + Const
Iterator + For..Of
Map + Set + WeakMap + WeakSet
Proxies
Symbols
Promises
Tail Calls
Function shorthand using the =>
syntax
this
as their surrounding codeReturns the value of the expression
Classic
var numbers = [1, 2, 3];
numbers.map(function(v) { return v * v }); // [1, 4, 9];
ECMAScript 6
var numbers = [1, 2, 3];
numbers.map( v => v * v ); // [1, 4, 9];
Classic
var numbers = [1, 2, 3];
numbers.map(function(v, idx) { return v * idx }); // [0, 2, 6];
ECMAScript 6
var numbers = [1, 2, 3];
numbers.map( (v, idx) => v * idx ); // [0, 2, 6];
Classic
var numbers = [1, 2, 3];
numbers.map( function(v, idx) { return { i: idx, v: v.toString() }; } );
// [{ i: 0, v: "1" }, { i: 1, v: "2" }, { i: 2, v: "3" }];
ECMAScript 6
var numbers = [1, 2, 3];
numbers.map( (v, idx) => ({ i: idx, v: v.toString() }) );
// [{ i: 0, v: "1" }, { i: 1, v: "2" }, { i: 2, v: "3" }];
Explicit return value, or undefined if no especified
Classic
var words = ['some', 'random', 'words'];
words.filter( function(w) {
var l = w.length;
return l % 2 === 0;
}); // ['some', 'random'];
ECMAScript 6
var words = ['some', 'random', 'words'];
words.filter( w => {
var l = w.length;
return l % 2 === 0;
}); // ['some', 'random'];
Classic
var words = ['some', 'random', 'words'];
words.forEach( function(w) {
console.log('Word:', w);
});
// Word: some
// Word: random
// Word: worlds
ECMAScript 6
var words = ['some', 'random', 'words'];
words.forEach( w => { // no return value
console.log('Word:', w);
});
// Word: some
// Word: random
// Word: worlds
Syntactic sugar over prototype-based inheritance
Does not introduces a new object-oriented inheritance model
Provide a much simpler and clearer syntax to create objects and dealing with inheritance
Class body and method definitions
constructor
this
Classic
var Person = function (name) {
this.name = name;
};
Person.prototype.sayHello = function() {
console.log("Hello, I'm " + this.name);
};
var john = new Person("John");
john.sayHello(); // Hello, I'm John
console.log('name:', john.name); // name: John
ECMAScript 6
class Person {
constructor (name) {
this.name = name; // properties accessed with this keyword
}
get nickname() {
return 'lil ' + this.name; // nickname only readable, never writable
}
sayHello() { //
console.log("Hello, I'm " + this.name);
}
}
var john = new Person('John');
john.sayHello(); // Hello, I'm John
console.log('name:', john.name); // name: John
console.log('nickname:', john.nickname); // Nickname: lil John
john.nickname = 'Johnny'; // Error
Classic
function Student(name, subject) { // Define the Student constructor
Person.call(this, name); // Calls parent constructor
this.subject = subject;
};
// Create a Student.prototype object that inherits from Person.prototype.
Student.prototype = Object.create(Person.prototype);
// Set the "constructor" property to refer to Student
Student.prototype.constructor = Student;
// Override the "sayHello" method
Student.prototype.sayHello = function(){
console.log("Hello, I'm " + this.name + ". I'm studying " + this.subject + ".");
};
// Add a "sayGoodBye" method
Student.prototype.sayGoodBye = function(){
console.log("Goodbye!");
};
var janet = new Student("Janet", "Applied Physics");
janet.sayHello(); // "Hello, I'm Janet. I'm studying Applied Physics."
janet.sayGoodBye(); // "Goodbye!"
// Check that instanceof works correctly
console.log(janet instanceof Person); // true
console.log(janet instanceof Student); // true
ECMAScript 6
class Student extends Person {
constructor(name, subject) {
super(name); // Calls parent constructor
this.subject = subject;
}
// Override the "sayHello" method
sayHello() {
console.log("Hello, I'm " + this.name + ". I'm studying " + this.subject + ".");
}
// Add a "sayGoodBye" method
sayGoodBye(){
console.log("Goodbye!");
};
}
var janet = new Student("Janet", "Applied Physics");
janet.sayHello(); // "Hello, I'm Janet. I'm studying Applied Physics."
janet.sayGoodBye(); // "Goodbye!"
// Check that instanceof works correctly
console.log(janet instanceof Person); // true
console.log(janet instanceof Student); // true
export
import
Named exports (several per module)
// circles.js
export const PI = 3.1415;
export function area(radius) {
return PI * radius * radius;
}
export function perimeter(radius) {
return 2 * PI * radius;
}
// app.js
import { area, perimeter } from 'circles'; // import some objects
console.log(area(5)); // 78.54
console.log(perimeter(3)); // 18.85
Named exports (several per module) 2
// circles.js
export const PI = 3.1415;
export function area(radius) {
return PI * radius * radius;
}
export function perimeter(radius) {
return 2 * PI * radius;
}
// app.js
import * as circles from 'circles'; // import whole module
console.log(circles.area(5)); // 78.54
console.log(circles.perimeter(3)); // 18.85
Default exports (one per module)
// library.js
export default function () { ... };
// app.js
import f from 'library'; // You can import it and use any name to refer to it
f();
Default and named exports
// underscore.js
export default function (obj) {
...
};
export function each(obj, iterator, context) {
...
}
export { each as forEach }; // some alias for an export
// app.js
import _, { each } from 'underscore';
// default import with no braces, named imports inside braces
foo: foo
propertiessuper
callsECMAScript 6
function SomeConstructor () {};
SomeConstructor.prototype.someMethod = function() {
console.log('someMethod executed');
}
var obj = {
// __proto__
__proto__: SomeConstructor.prototype,
// Shorthand for ‘parseInt: parseInt’
parseInt,
// Methods
toString() {
// Super calls
return "d: " + super.toString();
},
// Computed (dynamic) property names
[ 'prop_' + (() => 42)() ]: 42
};
console.log(obj.parseInt('2')*obj.parseInt('-1')); // -2
console.log(obj.toString()); // d: [object Object]
console.log(obj.prop_42); // 42
console.log(obj.someMethod.call()); // 'someMethod executed'
Syntactic sugar for constructing strings
String literals allowing embedded expressions
Allow
Enclosed by the back-tick `
They can contain placeholders indicated by dollar sign and braces: ${ }
Classic
var name = "Miguel";
console.log('Hi, ' + name + '!'); // Hi, Miguel!
ECMAScript 6
var name = "Miguel";
console.log(`Hi, ${name}!`); // Hi, Miguel!
Classic
var a = 5;
var b = 10;
console.log("Fifteen is " + (a + b) + " and\nnot " + (2 * a + b) + ".");
// "Fifteen is 15 and
// not 20."
ECMAScript 6
var a = 5;
var b = 10;
console.log(`Fifteen is ${a + b} and\nnot ${2 * a + b}.`);
// "Fifteen is 15 and
// not 20."
function fn() { return "I am a result. Rarr"; }
console.log(`foo ${fn()} bar`);
//=> foo I am a result. Rarr bar.
var user = {name: 'Caitlin Potter'};
console.log(`Thanks for getting this into V8, ${user.name.toUpperCase()}.`);
// Thanks for getting this into V8, CAITLIN POTTER.
Classic
console.log("string text line 1\n"+
"string text line 2");
// "string text line 1
// string text line 2"
ECMAScript 6
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
Tagged Templates transform a Template String by placing a function name before the template string
fn`Hello ${you}! You are looking ${adjective} today!`
// desugars into
fn(["Hello ", "! You are looking ", " today!"], you, adjective);
Can be useful for:
Allows binding using pattern matching
Support for arrays and objects
Fail-soft semantics, producing undefined values when impossible to bind a value to a variable
Classic
var foo = ["one", "two", "three"];
var one = foo[0];
var two = foo[1];
var three = foo[2];
ECMAScript 6
var foo = ["one", "two", "three"];
var [one, two, three] = foo;
// Assignment without declaration
var a, b;
[a, b] = [1, 2];
// Swapping variables
var a = 1, b = 3;
[a, b] = [b, a];
// Multiple return value
function f() { return [1, 2]; }
var a, b, array;
[a, b] = f(); // 1 to 1 assignment: a is 1, b is 2
array = f(); // store return value as an array: a is [1, 2]
// fail-soft
var [a] = [];
console.log(a === undefined); // true
Default values: Callee-evaluated default parameter values
Rest arguments: Turn an array into consecutive arguments in a function call
Spread values: passes each element of an array as an single argument
Default values: Callee-evaluated default parameter values
function f(x, y=12) {
// y is 12 if not passed (or passed as undefined)
return x + y;
}
console.log(f(3) === 15); // true
Rest arguments: Turn an array into consecutive arguments in a function call
function f(x, ...y) {
// y is an Array
return x * y.length;
}
console.log(f(3, "hello", true) === 6); // true
Spread values: passes each element of an array as an single argument
function f(x, y, z) {
return x + y + z;
}
// Pass each elem of array as argument
console.log(f(...[1,2,3]) === 6); // true
Block scoped bindings
Let: declares a block scope local variable, optionally initializing it to a value
var a = 5;
var b = 10;
if (a === 5) {
let a = 4; // The scope is inside the if-block
var b = 1; // The scope is inside the function
console.log(a); // 4
console.log(b); // 1
}
console.log(a); // 5
console.log(b); // 1
Const: creates a read-only named constant
const MY_FAV = 7;
MY_FAV = 20; // trying to modify constant after declaration throws an error
const MY_FAV = 20; // trying to redeclare a constant throws an error
var MY_FAV = 20; // throws error: the name MY_FAV is reserved for constant above
const FOO; // SyntaxError: const requires an initializer
const MY_OBJECT = {"key": "value"}; // const also works on objects
MY_OBJECT = {"OTHER_KEY": "value"}; // overwriting the object fails as above
MY_OBJECT.key = "otherValue"; // object attributes are not protected
Iterator: Establishes "iterable" protocol to allow objects to customize their iteration behaviour
for..of: convenient operator to iterate over all values of an iterable object
let fibonacci = {
[Symbol.iterator]() {
let pre = 0, cur = 1;
return {
next() {
[pre, cur] = [cur, pre + cur];
return { done: false, value: cur }
}
}
}
}
for (var n of fibonacci) {
if (n > 1000) // truncate the sequence at 1000
break;
console.log(n);
}
Iteration works if the code complies with those interfaces
// TypeScript syntax
interface IteratorResult {
done: boolean;
value: any;
}
interface Iterator {
next(): IteratorResult;
}
interface Iterable {
[Symbol.iterator](): Iterator
}
var myMap = new Map();
var keyObj = {},
keyFunc = function () {},
keyString = "a string";
// setting the values
myMap.set(keyString, "value associated with 'a string'");
myMap.set(keyObj, "value associated with keyObj");
myMap.set(keyFunc, "value associated with keyFunc");
myMap.size; // 3
// getting the values
myMap.get(keyString); // "value associated with 'a string'"
myMap.get(keyObj); // "value associated with keyObj"
myMap.get(keyFunc); // "value associated with keyFunc"
myMap.get("a string"); // "value associated with 'a string'"
// because keyString === 'a string'
myMap.get({}); // undefined, because keyObj !== {}
myMap.get(function() {}) // undefined, because keyFunc !== function () {}
var mySet = new Set();
mySet.add(1);
mySet.add(5);
mySet.add("some text");
var o = {a: 1, b: 2};
mySet.add(o);
mySet.has(1); // true
mySet.has(3); // false, 3 has not been added to the set
mySet.has(5); // true
mySet.has(Math.sqrt(25)); // true
mySet.has("Some Text".toLowerCase()); // true
mySet.has(o); // true
mySet.size; // 4
mySet.delete(5); // removes 5 from the set
mySet.has(5); // false, 5 has been removed
mySet.size; // 3, we just removed one value
var wm = new WeakMap();
// As there is no other reference to the key, the whole entry
// will be garbage collected
wm.set({}, { extra: 42 });
console.log(wm.size === undefined); // true
console.log(wm.has({})); // false
// No other reference to the object added, so it is garbage collected
var ws = new WeakSet();
ws.add({ data: 42 });
console.log(ws.has({ data: 42 })); // false
// obj holds a reference to the object so is not garbage collected
var obj = {a: 'string'};
ws.add(obj);
console.log(ws.has(obj)); // true
var target = { world: 'Mars'};
var handler = {
get: function (receiver, name) {
return `Hello, ${name}! from ${receiver[name]}`;
}
};
var p = new Proxy(target, handler);
console.log(p.world === 'Hello, world! from Mars'); // true
var target = function () { return 'I am the target'; };
var handler = {
apply: function (receiver, ...args) {
return 'I am the proxy, and ' + receiver(args);
}
};
var p = new Proxy(target, handler);
console.log(p() === 'I am the proxy, and I am the target'); // true
var sym1 = Symbol();
var sym2 = Symbol("foo");
var sym3 = Symbol("some description");
// It creates a new symbol each time
console.log(Symbol("foo") === Symbol("foo")); // false
// Can be used as a property key
var sym = Symbol("foo");
var obj = {
[sym]: 1
};
console.log(obj[sym]); // 1
var someLongProcess = function() {
console.log(`starting: ${new Date()}`);
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('some value');
}, 2000);
});
};
someLongProcess().then(function(value) {
console.log(`ending with ${value}: ${new Date()}`);
});
function factorial(n, acc = 1) {
'use strict';
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}
// Stack overflow in most implementations today,
// but safe on arbitrary inputs in ES6
factorial(100000)
Miguel Cobá