On Github miguelcoba / es6-features
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
Returns 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
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
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
ECMAScript 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á
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.