let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
With string
const [a, b, c, d, e] = 'hello';
With object
let { foo, bar } = { foo: "aaa", bar: "bbb" };
// which is essentially:
let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };
// default value
var {x, y = 5} = {x: 1};
// something comes in handy
let { log, sin, cos } = Math;
function example() {
return [1, 2, 3];
}
let [a, b, c] = example();
function example() {
return {
foo: 1,
bar: 2
};
}
let { foo, bar } = example();
Extract data from JSON
let jsonData = {
id: 42,
status: "OK",
data: [867, 5309]
};
let { id, status, data: number } = jsonData;
console.log(id, status, number);
// 42, "OK", [867, 5309]
Default funciton params
// instead of this || that
jQuery.ajax = function (url, {
async = true,
beforeSend = function () {},
cache = true,
complete = function () {},
crossDomain = false,
global = true,
// ... more config
}) { // ... do stuff };
Iterate through Map
var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');
for (let [key, value] of map) {
console.log(key + " is " + value);
}
// multi-line
`In JavaScript this is
not legal.`
console.log(`string text line 1
string text line 2`);
// string interpretation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`
// you can even do this
function fn() { return "Hello World"; }
`foo ${fn()} bar`
// foo Hello World bar
Iterate through string with for...of
for (let codePoint of 'foo') {
console.log(codePoint)
}
includes(), startsWith(), endsWith()
var s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
Array
Array.from to turn an array-like object into an array
let spans = document.querySelectorAll('span.name');
// map()
let names1 = Array.prototype.map.call(spans, s => s.textContent);
// Array.from()
let names2 = Array.from(spans, s => s.textContent)
Function
Default params
function Point(x = 0, y = 0) {
this.x = x;
this.y = y;
}
var p = new Point();
p // { x: 0, y: 0 }
// watch out for re-declaring let and const variables
function foo(x = 5) {
let x = 1; // error
const x = 2; // error
}
Rest param
function add(...values) {
let sum = 0;
for (var val of values) {
sum += val;
}
return sum;
}
add(2, 5, 3) // 10
// with arguments
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// with rest params
const sortNumbers = (...numbers) => numbers.sort();
// more examples
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
Spread operator
function push(array, ...items) {
array.push(...items);
}
function add(x, y) {
return x + y;
}
var numbers = [4, 38];
add(...numbers) // 42
Spread operator vs Rest parameterso
When using spread, you are expanding a single variable into more:
var abc = ['a', 'b', 'c'];
var def = ['d', 'e', 'f'];
var alpha = [ ...abc, ...def ];
// alpha == ['a', 'b', 'c', 'd', 'e', 'f'];
When using rest arguments, you are collapsing all remaining arguments of a function into one array:
function sum( first, ...others ) {
for ( var i = 0; i < others.length; i++ )
first += others[i];
return first;
}
// sum(1, 2, 3, 4) == 10;
Use spread to replace .apply()
// ES5
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f.apply(null, args);
// ES6
function f(x, y, z) {
// ...
}
var args = [0, 1, 2];
f(...args);
// practical example
// ES5
Math.max.apply(null, [14, 3, 77])
// ES6
Math.max(...[14, 3, 77])
// more example
// ES5
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
Array.prototype.push.apply(arr1, arr2);
// ES6
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
arr1.push(...arr2);
Stop using 'use strict' within function if default params, destructuring assignment and spread operator are used. To work around this, either use global strict mode (use strict as the first line of your script), or wrap function inside of an IIFE.
// error
function doSomething(a, b = a) {
'use strict';
// code
}
Practical use cases
Concat arrays
// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]
Work together with destructuring assignment
// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
Make array out of string (or any thing that implemented Iterator)
[...'hello']
// [ "h", "e", "l", "l", "o" ]
var nodeList = document.querySelectorAll('div');
var array = [...nodeList];
Arrow function
var f = v => v;
// same as
var f = function(v) {
return v;
};
// with params
var sum = (num1, num2) => num1 + num2;
var sum = function(num1, num2) {
return num1 + num2;
};
Return object without return
var getTempItem = id => ({ id: id, name: "Temp" });
Make callback function more intuitive
[1,2,3].map(function (x) {
return x * x;
});
[1,2,3].map(x => x * x);
'this points to whoever calls the function' rule no longer apply.
arrow function can't be used as constructor function.
no arguments object available, use rest params instead if you need one.
can't use yield hence arrow function can't be used as generator function.
Object
Shorthand
var foo = 'bar';
var baz = {foo};
baz // {foo: "bar"}
// same as
var baz = {foo: foo};
function f(x, y) {
return {x, y};
}
// same as
function f(x, y) {
return {x: x, y: y};
}
var o = {
method() {
return "Hello!";
}
};
// same as
var o = {
method: function() {
return "Hello!";
}
};
Use [] for property key
let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123
};
// this is also possible
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
obj.hello() // hi
Object.assign()
var target = { a: 1 };
var source1 = { b: 2 };
var source2 = { c: 3 };
Object.assign(target, source1, source2); // be aware: shallow copy
target // {a:1, b:2, c:3}
Object.values(),Object.entries()
let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };
for (let key of keys(obj)) {
console.log(key); // 'a', 'b', 'c'
}
for (let value of values(obj)) {
console.log(value); // 1, 2, 3
}
// Object.values(obj)
for (let [key, value] of entries(obj)) {
console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}
Practical use cases
Add instance property
class Point {
constructor(x, y) {
Object.assign(this, {x, y});
}
}
.catch returns yet another Promise, which allows you to chain another .then
var someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// throw x not define error in the next line
resolve(x + 2);
});
};
someAsyncThing()
.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
// carry on
Promise.all
var promises = [2, 3, 5, 7, 11, 13].map(function (id) {
return getJSON("/post/" + id + ".json");
});
Promise.all(promises).then(function (posts) {
// will only be invoked if all 6 promises had been fulfilled or any one of them failed
}).catch(function(reason){
// ...
});
// by naming convention
class Widget {
// public
foo (baz) {
this._bar(baz);
}
// private
_bar(baz) {
return this.snaf = baz;
}
}
// move it out of class
class Widget {
foo (baz) {
bar.call(this, baz);
}
}
function bar(baz) {
return this.snaf = baz;
}
// take the advantage of the uniqueness of Symbol
const bar = Symbol('bar');
const snaf = Symbol('snaf');
export default class myClass{
// public
foo(baz) {
this[bar](baz);
}
// private
[bar](baz) {
return this[snaf] = baz;
}
};
Inheritance
class ColorPoint extends Point {}
Super
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // must be done
this.color = color;
}
toString() {
return this.color + ' ' + super.toString();
}
}
Getter and Setter
class MyClass {
constructor() {
// ...
}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter: '+value);
}
}
let inst = new MyClass();
inst.prop = 123;
// setter: 123
inst.prop
// 'getter'
Static method
class Foo {
static classMethod() { // will be inherited by the sub classes
return 'hello';
}
}
Foo.classMethod() // 'hello'
var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
Module
Export variable
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
// same as
export {firstName, lastName};
Export function or class
export function multiply(x, y) {
return x * y;
};
// same as
function f() {}
export {f};
Import
import {firstName, lastName} from './profile';
// import as different name
import { lastName as surname } from './profile';
Import the whole module
// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
// app.js
import * as circle from './circle';
console.log('area:' + circle.area(4));
console.log('circule:' + circle.circumference(14));
Export and import default
// export-default.js
export default function () { // works with named function as well
console.log('foo');
}
// import-default.js
import customName from './export-default'; // any name you want
customName(); // 'foo'
export default function crc32() { }
import crc32 from 'crc32'; // this works as export default can only done once
export function crc32() { };
import {crc32} from 'crc32';
// modules.js
function add(x, y) {
return x * y;
}
export {add as default};
// same as
// export default add;
// app.js
import { default as xxx } from 'modules';
// same as
// import xxx from 'modules';
Export default enables:
import _ from 'lodash';
// or
import _, { each } from 'lodash';
Export default class
// MyClass.js
export default class { ... }
// main.js
import MyClass from 'MyClass';
let o = new MyClass();
Destructuring assignment
With Set
With default value
With string
With object
With function params
Practical use cases
Swap values
Return multiple values
Extract data from JSON
Default funciton params
Iterate through Map
Import named function from module
Strings
Template literals
Iterate through string with
for...of
includes(), startsWith(), endsWith()
Array
Array.from to turn an array-like object into an array
Array.of, to replace new Array()
find()
includes()
Practical use cases
Getting text content from queried elements
Function
Default params
Rest param
Spread operator
Spread operator vs Rest parameter so When using spread, you are expanding a single variable into more:
When using rest arguments, you are collapsing all remaining arguments of a function into one array:
Use spread to replace .apply()
Stop using 'use strict' within function if default params, destructuring assignment and spread operator are used. To work around this, either use global strict mode (
use strict
as the first line of your script), or wrap function inside of an IIFE.Practical use cases
Concat arrays
Work together with destructuring assignment
Make array out of string (or any thing that implemented Iterator)
Arrow function
Return object without
return
Make callback function more intuitive
With rest params
Things to be aware of when using arrow function
this
points to whoever calls the function' rule no longer apply.arguments
object available, use rest params instead if you need one.yield
hence arrow function can't be used asgenerator
function.Object
Shorthand
Use [] for property key
Object.assign()
Object.values(),Object.entries()
Practical use cases
Add instance property
Add methods to the prototype object
Clone object (breaking prototype chain)
Clone object (without breaking prototype chain)
Merge object
Add default options
Promise
if (/ succeeded /){ resolve(value); } else { reject(error); } });
then
returns another Promise which allows chain operationA simple example wrapping
timeout
Promise will be invoked right after it's created
Example with async loading images
Implement getJSON
ES6 flavour of writing the promise callback
Promise.prototype.catch
Always put your error handle callback in the
.catch
block.catch
returns yet another Promise, which allows you to chain another.then
Promise.all
Promise.race
Promise.prototype.done
Promise.prototype.finally
Class
Revisit how's done with ES5
Introduce
Class
in ES63 ways of adding private method in the Class
Inheritance
Super
Getter and Setter
Static method
Module
Export variable
Export function or class
Import
Import the whole module
Export and import default
Export default enables:
Export default class