ES2015
WHAT IS ECMASCRIPT?
May '95
Dec '95
Sep '95
1997
Aug '96
1999
1998
2009
2003
2015
2011
2016
Mocha (Brendan Eich, Netscape)
LiveScript
JavaScript
Edition 1
JScript (Microsoft)
Edition 2
Edition 3
Edition 4
Edition 5
Edition 5.1
Edition 6
Edition 7
ECMA-262 specification
- Latest finalised version ECMAScript6 (ES6, ES2015, Harmony)
- Change to yearly naming convention (ES7 = ES2016)
What is ES6?
- ECMAScript 6, also known as ECMAScript 2015, is the upcoming version of the ECMAScript standard.
- This standard is targeting ratification in June 2015.
- ES6 is a significant update to the language, and the first update to the language since ES5 was standardized in 2009.
COMPATIBILITY
- Native support in browsers still being implemented
- Compatibility table at http://kangax.github.io/compat-table/es6/
- Support in browsers through transpiling
TRANSPILATION
- Transpiler compiles code latest version -> older version
- ES5 widely supported by browsers -> ES6 should be compiled to ES5 for compatibility
- Two main ES6 -> ES5 transpilers:
- Traceur
- Babel
- Babel generally preferred:
- More readable transpiled code
- JSX support (compatibility with React.js)
- Alternatively use higher-level language implementing ES6 features
- CoffeeScript
- Dart
- Typescript (more later)
Transpilation
/*jshint esnext: true */
import Todo from './todo';
import {values} from './generators';
class TodoList {
constructor() {
this.todos = {};
this.length = 0;
}
add(text, done = false) {
let todo = new Todo(text, done);
this.todos[String(todo.timestamp)] = todo;
this.length++;
}
archiveCompleted() {
for (let todo of values(this.todos)) {
if (todo.done) this.delete(todo);
}
}
delete(todo) {
delete this.todos[String(todo.timestamp)];
this.length--;
}
getUncompletedCount() {
let count = 0;
for (let todo of values(this.todos)) {
if (!todo.done) count++;
}
return count;
}
}
export default TodoList;
/*jshint esnext: true */
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _todo = require('./todo');
var _todo2 = _interopRequireDefault(_todo);
var _generators = require('./generators');
var TodoList = (function () {
function TodoList() {
_classCallCheck(this, TodoList);
this.todos = {};
this.length = 0;
}
_createClass(TodoList, [{
key: 'add',
value: function add(text) {
var done = arguments.length <= 1 || arguments[1] === undefined ? false : arguments[1];
var todo = new _todo2['default'](text, done);
this.todos[String(todo.timestamp)] = todo;
this.length++;
}
}, {
key: 'archiveCompleted',
value: function archiveCompleted() {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _generators.values)(this.todos)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var todo = _step.value;
if (todo.done) this['delete'](todo);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator['return']) {
_iterator['return']();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}, {
key: 'delete',
value: function _delete(todo) {
delete this.todos[String(todo.timestamp)];
this.length--;
}
}, {
key: 'getUncompletedCount',
value: function getUncompletedCount() {
var count = 0;
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = (0, _generators.values)(this.todos)[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var todo = _step2.value;
if (!todo.done) count++;
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2['return']) {
_iterator2['return']();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
return count;
}
}]);
return TodoList;
})();
exports['default'] = TodoList;
module.exports = exports['default'];
ES6
ES5
Class
- ES5 objects inherit from Object.protoype
- Can instantiate and define methods using the protoype
function Client (firstname, lastname) {
this.id = undefined
this.firstname = firstname
this.lastname = lastname
}
Client.prototype.getFullName = function () {
return this.firstname + this.lastname
}
Client.prototype.setId = function () {
this.id = generateGuid()
}
ES5
ES6
class Client {
constructor(firstname, lastname) {
this.id = undefined
this.firstname = firstname
this.lastname = lastname
}
getFullName() {
return this.firstname + this.lastname
}
generateId() {
this.id = generateGuid()
}
}
- ES6 classes are 'syntactic sugar' on top of prototypal inheritance
Class
ES6
class Client {
constructor(firstname, lastname) {
this.id = undefined
this.firstname = firstname
this.lastname = lastname
}
getFullName() {
return this.firstname + this.lastname
}
generateId() {
this.id = generateGuid()
}
}
- Method signature notation - shorter, cleaner
- No commas between properties, methods
STATIC METHODS
ES6
class Client {
constructor(firstname, lastname) {
this.id = undefined
this.firstname = firstname
this.lastname = lastname
}
getFullName() {
return this.firstname + this.lastname
}
generateId() {
this.id = generateGuid()
}
static generateGuid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1)
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4()
}
}
- Can't be called on an instantiated class
- No access to 'this' properties/methods
- Most useful when associated with class, but don't need unique variables of instanced class
INHERITANCE
ES6 introduces the 'extend' keyword
class TCSClient extends Client {
this.evalSystem = "TCS"
}
var TCSClient = Object.create(Client);
TCSClient.evalSystem = "TCS"
ES6
ES5
Can override functions by re-implementing them in child class
class TCSClient extends Client {
getFullName() {
return this.firstname + " " +
this.lastname
}
}
var TCSClient = Object.create(Client)
TCSClient.prototype.getFullName() {
return this.firstname + " " +
this.lastname
}
ES5
ES6
Super()
ES5
function Client () {
this.vcNumber = undefined;
this.vcNumberPrefix = "";
}
Client.prototype.generateVCNumber = function () {
var number = Math.floor(Math.random() * 10000000);
this.vcNumber = this.vcNumberPrefix + pad(number, 7);
}
var TCSClient = Object.create(Client);
TCSClient.vcNumberPrefix = "A";
TCSClient.prototype.generateVCNumber = function() {
Client.prototype.generateVCNumber.call(this);
}
Can access methods of the parent object using super()
ES6
class DRClient extends Client {
this.vcNumberPrefix = "W";
generateVCNumber() {
super.generateVCNumber();
}
}
Modules
- Modules is a file that exports an API
- Implemented in ES6 as standard
- Exported bindings are available to other modules that import them
- Emulated in libraries such as Common JS, AMD before ES6
Default export
Only one default export per module
// ClientService.js
class ClientService {
clients = [];
addClient(client) {
this.clients.add(client);
}
}
export default ClientService;
import ClientService from './ClientService';
class ClientComponent {
submitClient(client) {
ClientService.addClient(client);
}
}
Named exports
- Many exports per module
- Can use with default export
- Can be expressed as a list
// Constants.js
var $BANKRUPTCY_MIN_DEBT = 1001;
var $SEQUESTRATION_MIN_DEBT = 3000;
export $BANKRUPTCY_MIN_DEBT;
export $SEQUESTRATION_MIN_DEBT;
// Constants.js
var $BANKRUPTCY_MIN_DEBT = 1001;
var $SEQUESTRATION_MIN_DEBT = 3000;
export { $BANKRUPTCY_MIN_DEBT,
$SEQUESTRATION_MIN_DEBT}
or
Importing named exports
// Constants.js
var $BANKRUPTCY_MIN_DEBT = 1001;
var $SEQUESTRATION_MIN_DEBT = 3000;
export $BANKRUPTCY_MIN_DEBT;
export $SEQUESTRATION_MIN_DEBT;
import {$BANKRUPTCY_MIN_DEBT,
$SEQUESTRATION_MIN_DEBT} from './Constants';
function checkSomething(
return $BANKRUPTCY_MIN_DEBT > $SEQUESTRATION_MIN_DEBT;
}
rename when importing
// Constants.js
var $BANKRUPTCY_MIN_DEBT = 1001;
var $SEQUESTRATION_MIN_DEBT = 3000;
export $BANKRUPTCY_MIN_DEBT;
export $SEQUESTRATION_MIN_DEBT;
import {$BANKRUPTCY_MIN_DEBT as minDebt,
$SEQUESTRATION_MIN_DEBT as seq} from './Constants';
function checkSomething(
return minDebt > seq;
}
Importing the entire module
- A namespace import must have an alias
- Any default export would be placed in alias.default
// IncomesController.js
export var incomeSupport;
export var jobSeekers;
export var incapacity;
export function totalBenefitIncome () {
this.valIncomeSupport +
this.valJobSeekers +
this.valIncapacity;
}
import * as incomes from './IncomesController'
function submitIncomes() {
incomes.incomeSupport = this.valIncomeSupport;
incomes.jobseekers = this.valJobseekers;
incomes.incapacity = this.valIncapacity;
this.valTotalBenefitIncome = incomes.TotalBenefitIncome;
}
Symbol
New primitive type
Similar to strings:
- Immutable
- Can't add properties on them (as with any primitive)
- Can be used as a property key
var mySymbol = Symbol("description");
console.log(typeof mySymbol); // 'symbol'
Unique (even where description is same)
Symbol('foo') === Symbol('foo'); // false
Does not use 'new' operator
var symbol = new Symbol(); // TypeError
Symbol
Symbol
- Avoiding name clashes in property keys - e.g.
- Creates a unique property in scope - no collisions
if (element.isMoving) {
smoothAnimations(element);
}
element.isMoving = true;
var isMoving = Symbol("isMoving");
...
if (element[isMoving]) {
smoothAnimations(element);
}
element[isMoving] = true;
var myArray = ['a', 'b', 'c'];
var myIterable = myArray[Symbol.iterator]();
> iterable.next()
{ value: 'a', done: false };
> iterable.next()
{ value: 'b', done: false };
> iterable.next()
{ value: 'c', done: false };
> iterable.next()
{ value: undefined, done: true };
Symbol
Can flag an object as having a set of common methods by attaching certain symbols, e.g.
Iterable objects use the 'well-known' Symbol.iterator
- myArray has Symbol.iterator property:
- each item in collection has 'value' and 'done' properties
- can iterate through list with next()
ITERATORS
- ES6 introduces iterator and iterable protocols
- 'Iterability' involves data sources and data consumers
ITERATORS
- Data consumers:
- for - of loops
- Array.from
- spread operator (more later)
- Data sources: some built-ins are iterable by default in ES6
- Arrays
- Strings
- Maps
- Sets
- DOM data structures (e.g. querySelectorAll method)
- To comply with the iterator protocol:
- Object must have a next() method
- The next() method takes no arguments
- The next() method returns an object with at least:
- A 'done' property: true (sequence done), or false (may be more values)
- A 'value' property: current item in sequence
ITERATORS
- The Symbol.iterator is used to assign an 'iterator' to any object
- Symbol.iterator equates to a method that must return an object that complies with the iterator protocol.
[Symbol.iterator]: () => ({
items: ['f', 'o', 'o'],
next: function next() {
return {
done: this.items.length === 0,
value: this.items.shift()
}
}
})
next() method (no args)
returns Object with done, value
ITERATORS
function* myGenerator() {}
// or
function *myGenerator() {}
GENERATORS
- Special kind of iterator
- 'Generator function' declared, using asterisk notation:
Generator functions contain 'yield' expressions
- On 'yield' expression, function:
- Suspends execution
- Emits a value
function* myGenerator() {
yield 'f';
console.log('o');
yield 'o';
console.log('b');
yield 'a';
console.log('r');
}
var fooBar = myGenerator();
for(var item of fooBar) {
console.log(item); // 'f' 'o' 'o' 'b' 'a' 'r'
}
GENERATORS
function *myGenerator(x) {
var y = x + 3;
var z = 1 + (yield(y));
return z;
}
var gen = myGenerator(2);
console.log( gen.next() );
console.log( gen.next(6) );
1
2
3
4
7
6
5
GENERATORS
- Calling next() on Generator object starts function or resume from last yield expression
- Params passed to next() replace yield expression
- myGenerator function instantiated with param x = 2
- next() called on generator function. No 'yield' expression encountered yet, so no param
- execution paused on yield expression; var y passed out as 5
- console logs { value: 5, done: false }
- execution resumes with yield expression as passed in param (6)
- since yield expression is 6, z becomes 7 (1 + 6)
- end of generator function; console logs { value: 7, done: true }
GENERATORS
- Allows 2-way message passing into / out of functions
- Allows for cooperative concurrency of programming
"let" and "const"
- Alternatives to declaring a variable with 'var'
- 'let' block-scopes variables rather than var's function- scoping
"let" and "const"
Hoisting - variables and function declarations get pulled to the top of their scope
- Allows references to variables declared later without exceptions, but
- Results can be unintuitive
- Variables should be declared at top of function to avoid errors
var foo = true;
function bar() {
if (!foo) {
var foo = "Foo is false!"
};
console.log(foo)
}
bar()
> Foo is false!
var foo;
function bar() {
var foo;
if (!foo) {
foo = "Foo is false!"
};
console.log(foo);
}
foo = true;
bar();
ES5
ES5
Console
var x = 1;
if (x) {
var x = 2;
};
console.log(x);
> 2
{ } blocks do not create a new scope
"let" and "const"
ES5
What if we want a temporary scope for the inner x?
Console
var x = 1;
if (x) {
(function () {
var x = 2;
})
};
console.log(x);
> 1
ES5
Console
Could create a new function scope
"let" and "const"
var x = 1;
if (x) {
let x = 2;
}
console.log(x);
> 1
ES6
Console
- Using 'let' allows for block-scoping ( {} )
- Maintains encapsulation principles
- Allows same variable names where appropriate
const stuff = { things: ['chair', 'desk', 'computer'] };
const stuff = { things: ['chair', 'desk', 'computer'] };
stuff = {}; // fails
console.log(stuff.things); // ...
const stuff = { things: ['chair', 'desk', 'computer'] };
stuff.things.push('pot plant');
console.log(stuff.things);
// chair,desk,computer,pot plant
"let" and "const"
Const
- also block-scoped
- must be decalred using an initializer
- can only be assigned to once
- will fail silently if assigned again
- does not make the assigned value itself immutable
Arrow FUNCTIONS
- Also known as lambda expressions
- Makes code more 'terse'
var arrow = function() {}
var arrow = () => {}
becomes
function() {}
() => {}
becomes
- 'return' keyword implied for single expressions in function body
- No parentheses required for 1 argument
function(a) { return a * a }
a => a * a
becomes
- Parentheses for 0, or >1 arguments
function(a, b) { return a + b }
(a, b) => a + b
becomes
Arrow FUNCTIONS
- A 'fat arrow' takes the place of the 'function' keyword
function Counter() {
var that = this;
that.seconds = 0;
setInterval(function() {
that.seconds++
}, 1000);
}
function Counter() {
this.seconds = 0;
setInterval(function() {
this.seconds++
}.bind(this), 1000);
}
Arrow FUNCTIONS
In ES5, functions create their own scope
- Calling 'this' within the function refers to itself; not the scope outside the function
- To bring outside scope into the function, store 'this' in a variable, or use .bind()
ES5
function Counter() {
this.seconds = 0;
setInterval(function() {
this.seconds++
}.bind(this), 1000);
}
function Counter() {
this.seconds = 0;
setInterval(() => this.seconds++, 1000);
}
Arrow FUNCTIONS
- Arrow functions are bound to their lexical scope
- 'this' in an arrow function is the same as the outer scope
- Best used for functions with low amount of arguments/statements
- Can't name arrow functions
ES5
ES6
Previously only one collection type in JavaScript (Array)
COLLECTION TYPES
- Arrays only use numeric indices
- Objects used when non-numeric indices necessary
- Map
- A key-value data structure new in ES6
- Exists in many other languages
ES5 maps often created using regular Objects
var hashMap = {};
function add(key, value) {
hashMap[key] = value;
}
function get(key) {
return hashMap[key];
}
add('request', { description: 'Simplified HTTP request client' });
add('moment', { description: 'Parse, validate, manipulate, and display dates' });
add('lodash', { description: 'The modern build of lodash modular utilities' });
COLLECTION TYPES
var registry = {};
function add(element, meta) {
registry[element] = meta;
}
function get(element) {
return registry[element];
}
add(document.getElementById("wages-panel"), { display: true });
add(document.getElementById("child-income-panel"), { display: false });
add(document.getElementById("benefits-panel"), { display: true });
add(document.getElementById("otherincome-panel"), { display: true });
COLLECTION TYPES
Problems with this approach:
- Only allows strings as keys
- Might want to use non-string values as keys
- Here the <div> element will be cast to string [Object HTMLDivElement]
Maps allow for any type to be used as key or value
var map = new Map();
map.set(new Date(), function today() {});
map.set(() => 'key', { foo: 'bar' });
map.set(Symbol('items'), [1, 2]);
COLLECTION TYPES
ES5
for (let key in object) {
if (object.hasOwnProperty(key)) {
console.log(key, object[key]);
}
}
for (let key in object) {
if (object.hasOwnProperty(key) &&
typeof object[key] !== "function") {
console.log(key, object[key]);
}
}
COLLECTION TYPES
- Maps have many useful iteration features
- To iterate over a javascript object used as a map:
ES5
- Have to avoid properties from the object prototype being included
- Have to avoid methods from the prototype object being included
ES5
for (let key of map.keys()) {
console.log(key);
}
for (let value of map.values()) {
console.log(value);
}
for (let entry of map) {
console.log(entry[0], entry[1]);
}
COLLECTION TYPES
- With Maps, no unwanted properties /methods 'leaking' from prototype to deal with
- Maps can iterate on keys, values or entries
- 'entries()' default iterator for Maps
- each key-value pair stored as two item array
ES6
COLLECTION TYPES
WeakMap
- A subset of Map, with some limitations
- Not iterable - no .entries(), .keys(), .values() or clear()
- Can use .has(), .get(), .set(), .delete()
- Every key must be an object - value types not admitted
- A WeakMap holds references to its keys weakly
- i.e. if no other references to a key, the entry will be garbage collected
- Why use a WeakMap?
- Very specific use cases
- Mapping values to objects that might disappear in future
const privateData = new Map();
class myClass {
constructor (name, age) {
privateData(this, { name: name, age: age });
}
getname () {
return privateData.get(this).name;
}
getAge() {
return privateData.get(this).age;
}
}
export default MyClass;
COLLECTION TYPES
- No concept of private class variables in ES6
- Use case - Private class variables
- Still a reference to Map when myClass instance destroyed
- When myClass destroyed no references to key (this) exists
- privateData will be garbage collected and memory freed
let answersMap = new WeakMap();
let childBenefit = document.getElementById('child-benefit');
myElement.addEventListener('change', function() {
var answerFrequency = getFrequency();
answersMap.set(childBenefit, {frequency: answerFrequency}
}, false);
let childNumber = document.getElementById('child-number')
if(childNumber.number === 0) {
childBenefit.parentNode.removeChild(childBenefit)
}
console.log(answerMap.get(childBenefit) // undefined
COLLECTION TYPES
Storing data on a DOM element
- Storing the frequency of an answer on the DOM element
- If childBenefit key removed, entry is garbage collected
COLLECTION TYPES
- Set
- Very similar to map, but only have values
- Values used as keys, so must be unique
- no set.get() (get(value) => value)
- set.set becomes set.add
- use set when all values must be unique
- WeakSet
- As Map -> WeakMap
- Not iterable
- No other references to value - garbage collection
set
var text = `
This is a template literal
'It can span multiple lines'
"And can contain quotation marks"
`
var text = (
'This is the old method\n' +
'for strings spanning\n' +
'several lines'
)
var text = [
'Or',
'perhaps',
'this'
].join('\n')
TEMPLATE LITERALS
- A string wrapped in backticks ( ` )
- Can be multiline
- Strings can contain ' and " characters without escaping
ES5
ES6
var text = `the time and date is ${new Date().toLocaleString()}`
var a = 6;
console.log(`The number is ${a}`)
TEMPLATE LITERALS
Can interpolate expressions with ${expression}
var foo = { bar: 'bar' }
console.log(foo.bar) // 'bar'
var foo = { bar }
console.log(foo.bar) // 'bar'
OBJECT LITERALS
If property value matches property name, can omit value
ES5
ES6
var foo = 'bar'
var baz = { [foo]: 'qux' }
console.log(baz)
// { bar: 'qux' }
var foo = { [bar + baz]: 'qux' }
console.log(foo)
// { barbaz: 'qux' }
function getAnswerModel (dataItem, amt, frequency) {
return {
['ans_' + dataItem] : {
amount: amt;
frequency: freq
}
}
}
OBJECT LITERALS
Can compute property names using []
Possible use case:
var foo = {
bar(baz) { }
}
var foo = {
bar: function(baz) { }
}
OBJECT LITERALS
Declaring methods on an object
ES5
ES6
var clientDetails = {
userName: 'Joe Bloggs',
get name() {
return this.userName
},
set name(value) {
if (!value) {
throw new Error('Name invalid')
}
this.userName= value
}
}
OBJECT LITERALS
Getters and setters declared on functions
let myObject = { foo:'bar', baz: 'qux' }
let { foo, baz } = myObject
console.log(foo) // 'bar'
console.log(baz) // 'qux'
ASSIGNMENT DESTRUCTURING
An object literal lets us create multiple properties at the same time
An object pattern lets us extract multiple properties at the same time
Properties mapped to aliases
let myObject = { foo:'bar', baz: 'qux' }
let { norf: a } = myObject
console.log(a) // undefined
Properties can be mapped to aliases
let { foo : f, baz : b } = myObject
console.log(f) // 'bar'
console.log(b) // 'qux'
ASSIGNMENT DESTRUCTURING
Properties not found are saved as undefined
let myObject = { foo: [{ bar: 'baz', qux: 'norf' }] }
let { foo: [{ bar: a }] } = myObject
console.log(a) // 'baz'
let myObject = { foo:'bar', baz: undefined }
let { baz = 'default' } = myObject
console.log(baz) // 'default'
ASSIGNMENT DESTRUCTURING
Can define default values if 'pulled' property is undefined
Patterns can be nested arbitrarily deeply
let [, x, y] = [1, 2, 3]
console.log(x) // 2
console.log(y) // 3
let [x, y] = [1, 2, 3]
console.log(x) // 1
console.log(y) // 2
ASSIGNMENT DESTRUCTURING
Similarly, for arrays
Can skip over items not cared about
function swapIf () {
var left = 10;
var right = 20;
var aux;
if(right > left) {
aux = right;
right = left;
left = aux;
}
}
function swapIf () {
var left = 10
var right = 20
if(right > left) {
[left, right] = [right, left]
}
}
ASSIGNMENT DESTRUCTURING
Can swap variables without need for a temporary variable
ES5
ES6
function displayNameAge ( {name, age} ) {
console.log(`${name} is ${age} years old`)
}
displayNameAge( { age: 27, name: 'John'} ) // 'John is 27 years old'
ASSIGNMENT DESTRUCTURING
Can destructure a function's parameter list
function getCoordinates() {
return {
x: 5,
y: 22
}
}
var {x, y} = getCoords()
console.log(x) // 5
console.log(y) // 22
function getCoordinates() {
return {
x: 5,
y: 22
}
}
var object = getCoordinates();
var x = object.x;
var y = object.y;
console.log(x) // 5
console.log(y) // 22
ASSIGNMENT DESTRUCTURING
Possible use cases
More terse interaction with returned objects
ES5
ES6
function random() ( {min=1, max=100} ) {
return Math.floor(Math.random() * (max - min) + min
}
console.log(random( {} )) // 67
console.log(random( { max: 20 } ) // 11
ASSIGNMENT DESTRUCTURING
Possible use cases
Define default options for a method
SPREAD/REST PARAMETERS
Rest parameters - create an array out of a function's arguments
- ES5 - used 'arguments' variable to work with large numbers of arguments
function concat() {
return Array.prototype.slide.call(arguments).join(' ')
}
var result = concat('Lorem', 'ipsum', 'dolor', 'sit', 'amet')
console.log(result) // 'Lorem ipsum dolor sit amet'
- Using rest parameter syntax
function concat(...words) {
return words.join(' ')
}
var result = concat('Lorem', 'ipsum', 'dolor', 'sit', 'amet')
console.log(result) // 'Lorem ipsum dolor sit amet'
ES5
ES6
function concat(prefix, suffix, ...words) {
return prefix + words.join(' ') + suffix
}
var result = concat('START', 'END', 'Lorem', 'ipsum', 'dolor', 'sit', 'amet')
console.log(result) // 'START Lorem ipsum dolor sit amet END'
function concat() {
var words = Array.prototype.slide.call(arguments);
var prefix = words.shift();
var suffix = words.shift();
return prefix + words.join(' ') + suffix;
}
var result = concat('START', 'END', 'Lorem', 'ipsum', 'dolor', 'sit', 'amet')
console.log(result) // 'START Lorem ipsum dolor sit amet END'
SPREAD/REST PARAMETERS
If 'arguments' was used, need to cut first two params by shifting
If other parameters, rest param must be rightmost
ES5
ES6
var missing = [4, 5, 6]
var sequence = [1, 2, 3, ...missing, 7, ,8 , 9]
SPREAD/REST PARAMETERS
Spread operator
- Passes an array as arguments to a function
- Prefix array with '...'
To recap:
- spread/rest operators both use '...' syntax
- Rest operator extracts data (creates array from parameters)
- Spread operator constructs data (inserts parameters from array)
var promise = new Promise(function(resolve, reject) {
// do something
if( /* thing was done */ ) {
resolve("Success");
}
else {
reject(Error("Failed"));
}
});
promise.then(function(result) {
// Action on success
}, function(err) {
// Action on error
});
Promise
Creating a promise:
Using a promise:
Takes one argument:
- callback with 'resolve' and 'reject' params
- Do something with the callback (perhaps async)
- Call resolve() if worked
- Call reject() if not
then() takes two arguments:
- callback for success case
- callback for failure case
Useful links
http://habrahabr.ru/post/175371/ Обзор ECMAScript 6, следующей версии JavaScript
http://habrahabr.ru/post/241275/ Ecmascript 6 — что можно использовать уже сейчас
http://es6-features.org/ New Features: Overview & Comparison
http://codecondo.com/learn-ecmascript-6-resources-javascript-devs/
18 Resources on ES6 for JavaScript Developers
THANKS FOR YOUR ATTENTION
ES2015
ES2015
By Dima Pikulin
ES2015
- 1,830