On Github turnbullm / js-2015-preso
#1
var title = ['Welcome', 'To', 'Javascript', '2015'] .join(' ') .toLowerCase()
#2
define "title" = create Array("Welcome", "To", "Javascript", "2015") then, implode with ' ' then, stringToLower
var title = ['Welcome', 'To', 'Javascript', '2015'] .join(' ') .toLowerCase()
Who decided this is Javascript?
Not much help...
Finalized in 2009
Object.keys() Date.toISOString() Date.now() JSON.parse() JSON.stringify() String.trim() Array.isArray() Array.indexOf() Array.forEach() Array.map() Array.filter()
Let's fast forward...
6 years since ECMAScript Version 5
Also known as...
Start using it now, or be left behind!
These are all popular and influential frameworks
They are all using ES6 now!
What about browser support?
November 2015
IE10 7% Safari 6 12% IE11 16% Safari 7 & 8 21% Safari 9 54% Chrome 65% Firefox 74% IE Edge 84%Support will improve over time
Support will improve over time
fancyES6Code();
regularES5Code();
fancySassCode
regularCssCode
> babel main.js
// main.js require("babel-core/register"); // ES6 here
<script src="babel-core/browser.js"></script> <script src="main.es6.js"></script>
.pipe(babel())
grunt.initConfig({ "babel": {} })
25 new features
var myBestFriend = 'Barry'; if (true) { var myBestFriend = 'Anthony'; } console.log( myBestFriend ); // ???
var myBestFriend = 'Barry'; if (true) { var myBestFriend = 'Anthony'; } console.log( myBestFriend ); // Anthony
var numbers = [1, 5, 10]; // Add numbers together var result = 0; for (var i = 0; i < numbers.length; i++) { var number = numbers[i]; result += number; } console.log( result ); // 16 console.log( i ); // 3 console.log( number ); // 10
Limits variable to block scope
let myBestFriend = 'Barry'; if (true) { let myBestFriend = 'Anthony'; console.log( myBestFriend ); // Anthony } console.log( myBestFriend ); // Barry
let numbers = [1, 5, 10]; let result = 0; for (let i = 0; i < numbers.length; i++) { let number = number[i]; result += number; } console.log( result ); // 16 console.log( i ); // undefined console.log( number ); // undefined
This is how most would expect var to behave
Use let instead of var
(unless you really need var scoping)
Value that cannot be altered
const myConstant = 'never changes'; myConstant = 'can I change it?'; // NO!
Use const instead of let
Guarantees references won't be overridden
If you need references overridden, use let
const testString = 'anthony';
testString.startsWith('a'); // true testString.startsWith('ant'); // true // Second parameter: position to begin searching testString.startsWith('thon', 2); // true
const testString = 'anthony';
testString.includes('tho'); // true // Second parameter: position to begin searching testString.includes('ant', 1); // false
const testString = 'anthony';
testString.endsWith('ony'); // true // Second parameter: clip string to this length testString.endsWith('hon', 1); // false testString.endsWith('a', 1); // true testString.endsWith('hon', testString.length - 1); // true
const friends = [ { name: 'Barry', species: 'Bear' }, { name: 'Anthony', species: 'Anteater' } ]; const myBestFriend = friends.find(function(friend) { return friend.name === 'Barry'; }); console.log( myBestFriend ); // { name: 'Barry', species: 'Bear' } const myBestFriendIndex = friends.findIndex(function(friend) { return friend.name === 'Barry'; }); console.log( myBestFriendIndex ); // 0
Converts objects to an array
const myArray = Array.from(notAnArray);
Works with either;
Array.from(document.querySelectorAll('img')); Array.from(jQuery('img')); Array.from("test"); // ["t", "e", "s", "t"]
const sentence = joinWords('I', 'love', 'Barry');
function joinWords(word1, word2, word3) { // Join the words and return them }
function joinWords() { const words = Array.prototype.slice.call(arguments); // Join the words and return them }
Allows expressions to be expanded into arguments
Represented by 3 dots
function joinWords(...words) { // 'words' is an array! // Join the words and return them }
const sentence = joinWords('I', 'love', 'Barry'); // This works
const sentence = joinWords('I', 'love', 'Barry'); // This works const words = ['I', 'love', 'Barry']; const sentence = joinWords(words); // This doesn't work
// Could try alter joinWords function to accept an array? const sentence = joinWords(words);
const sentence = joinWords.apply(null, words);
const words = ['I', 'love', 'Barry']; const sentence = joinWords(...words); const sentence = joinWords('I', 'love', 'Barry'); // Same thing!
const words = ['I', 'love']; const sentence = joinWords(...words, 'my', ...['friend', 'Barry']); const sentence = joinWords('I', 'love', 'my', 'friend', 'Barry'); // Same thing!
const words = ['I', 'love', 'Barry']; const wordsCopy = [...words];
const position = [50, 200];
const x = position[0]; const y = position[1];
const [x, y] = position;
Works with spreads
const [a, b, ...rest] = [1, 2, 3, 4, 5]; console.log( a ); // 1 console.log( b ); // 2 console.log( rest ); // [3, 4, 5]
Works even better with objects
function getPosition() { return { x: 50, y: 200, z: 13 }; }
const { x, y } = getPosition();
const { z : zIndex } = getPosition(); console.log( zIndex ); // 13
const { a = 0 } = getPosition(); console.log( a ); // 0
function getPosition(something) { const x, y, z; // Do some calculation magic // Populate x, y, z constants // ES5 return { x: x, y: y, z: z }; // ES6 return { x, y, z }; // ES6 return { x, y, z }; }
const name = 'Bob'; const activity = 'running'; const place = 'library';
// ES5 const sentence = name + ' is ' + activity + ' to the ' + place;
// ES6 const sentence = `${name} is ${activity} to the ${place}`;
// ES5 const story = '"My name is ' + name + '" said ' + name + '.\n' + '"I\'m ' + activity + ' to the ' + place + '", he continued.\n' + 'Then ' + name + ' went ' + activity + ' to the ' + place + '.';
// ES6 const story = `"My name is ${name}" said ${name}. "I'm ${activity} to the ${place}", he continued. Then, ${name} went ${activity} to the ${place}.`;
function displayMessage(message) { // Some magic here to display the message } function removeMessage(message) { // Some magic here to remove the message }
Stop duplicate messages from displaying
Stop duplicate messages from displaying
function displayMessage(message) { // Some magic here to display the message } function removeMessage(message) { // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = []; function displayMessage(message) { // Some magic here to display the message } function removeMessage(message) { // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = []; function displayMessage(message) { messagesDisplayed.push(message); // Some magic here to display the message } function removeMessage(message) { // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = []; function displayMessage(message) { messagesDisplayed.push(message); // Some magic here to display the message } function removeMessage(message) { messagesDisplayed.splice(messagesDisplayed.indexOf(message), 1); // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = []; function displayMessage(message) { if (messagesDisplayed.indexOf(message) > -1) { return false; } messagesDisplayed.push(message); // Some magic here to display the message } function removeMessage(message) { messagesDisplayed.splice(messagesDisplayed.indexOf(message), 1); // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = []; function displayMessage(message) { if (messagesDisplayed.indexOf(message) > -1) { return false; } messagesDisplayed.push(message); // Some magic here to display the message } function removeMessage(message) { messagesDisplayed.splice(messagesDisplayed.indexOf(message), 1); // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = []; function displayMessage(message) { // Check if message has already been displayed if (messagesDisplayed.indexOf(message) > -1) { return false; } messagesDisplayed.push(message); // Some magic here to display the message } function removeMessage(message) { // Remove message as displayed messagesDisplayed.splice(messagesDisplayed.indexOf(message), 1); // Some magic here to remove the message }
A new type of object
const mySet = new Set();
Store unique values of any type
mySet.add('test'); mySet.add({ testObject: true });
Similar to an array, but easier to use:
mySet.has('test'); // true mySet.delete('test'); mySet.clear(); mySet.size; mySet.keys(); mySet.values(); mySet.entries(); mySet.forEach();
Stop duplicate messages from displaying
function displayMessage(message) { // Some magic here to display the message } function removeMessage(message) { // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = new Set(); function displayMessage(message) { // Some magic here to display the message } function removeMessage(message) { // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = new Set(); function displayMessage(message) { messagesDisplayed.add(message); // Some magic here to display the message } function removeMessage(message) { // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = new Set(); function displayMessage(message) { messagesDisplayed.add(message); // Some magic here to display the message } function removeMessage(message) { messagesDisplayed.delete(message); // Some magic here to remove the message }
Stop duplicate messages from displaying
const messagesDisplayed = new Set(); function displayMessage(message) { if (messagesDisplayed.has(message)) { return false; } messagesDisplayed.add(message); // Some magic here to display the message } function removeMessage(message) { messagesDisplayed.delete(message) // Some magic here to remove the message }
const messagesDisplayed = new Set(); function displayMessage(message) { if (messagesDisplayed.has(message)) { return false; } messagesDisplayed.add(message); // Some magic here to display the message } function removeMessage(message) { messagesDisplayed.delete(message) // Some magic here to remove the message }
What if hundreds of messages are displayed?
const testMessage = { contents: 'Barry is such a handsome bear' }; displayMessage(testMessage); const importantMessage = { contents: 'Anteaters suck', important: true }; displayMessage(importantMessage); // etc... (hundreds of these)
What if hundreds of messages are displayed?
const messagesDisplayed = new Set(); function displayMessage(message) { if (messagesDisplayed.has(message)) { return false; } messagesDisplayed.add(message); // Some magic here to display the message }
Similar to the Set object
Used for storing objects
Use Weak Sets when storing objects
const weakSet = new WeakSet(); weakSet.add(object); weakSet.has(object); weakSet.delete(object);
const myMap = new Map();
myMap.set('testKey', 'testValue');
May have used objects in ES5
const myMap = { 'testKey': 'testValue' }
Maps are more readable, and easier to use
const myMap = new Map(); myMap.set('testKey', 'testValue'); myMap.has('testKey'); // true myMap.get('testKey'); // 'testValue' myMap.delete('testKey'); myMap.clear(); myMap.size; myMap.keys(); myMap.values(); myMap.entries(); myMap.forEach();
The same concept as Weak Set
const weakMap = new WeakMap(); weakMap.set(object, value); weakMap.has(object); weakMap.get(object); weakMap.delete(object);
The keys are weak, not the value
Iterating arrays in ES5
Lots of choices
None are great
for (var index = 0; index < myArray.length; index++) { var value = myArray[index]; // ... }
myArray.forEach(function(value, index) { // ... });
for (var index in myArray) { var value = myArray[index]; // ... }
Iterating arrays in ES6
One choice
It's great!
for (let value of myArray) { // ... }
for (let index of myArray.keys()) { // ... }
for (let [index, value] of myArray.entries()) { // ... }
Works for any iterable object
For everything else, either;
function displayMessage(content, priority = 1) { console.log(`Priority: $(priority)`); // Some magic here to display the message } displayMessage('Hello, I am a message'); // Priority: 1 displayMessage('Something went wrong!', 10); // Priority: 10
function displayMessage(content, priority = 1, position = { x: 0, y: 0 }, title = null) { // Some magic here to display the message }
displayMessage('Default message'); displayMessage('Centered message', 1, { x: '50%', y: '50%'}); displayMessage('Error message with title', 10, { x: 0, y: 0 }, 'Uh oh');
function displayMessage(content, { priority = 1, position = { x: 0, y: 0 }, title = null } = {}) { // Some magic here to display the message }
displayMessage('Default message'); displayMessage('Centered message', { position: { x: '50%', y: '50%' } }); displayMessage('Error with title', { priority: 10, title: 'Uh oh' });
const defaultMessage = { content: 'Default message' }; const centeredMessage = { content: 'Centered message', position: { x: '50%', y: '50%' } }; const errorMessage = { content: 'Error message with title', priority: 10, title: 'Uh oh' };
Is there a better way to represent a message?
Custom type of object
Has its own functions and properties
const myObject = new Object();
const myArray = new Array();
const myCustomObject = new CustomObject(); myCustomObject.exampleFunction(); myCustomObject.exampleProperty = 'testing'; console.log( myCustomObject.exampleProperty ); // 'testing'
class CustomObject { exampleFunction() { this.exampleProperty = 'testing'; } anotherExampleFunction() { this.exampleFunction(); } }
class Message { getContent() { return 'Hello, I am a message'; } } const myMessage = new Message(); console.log( myMessage.getContent() ); // Hello, I am a message
All these lines of code to create messages?!
// Create test message class TestMessage { getContent() { return 'Hello, I am a test message'; } } const myTestMessage = new TestMessage(); // Create error message class ErrorMessage { getContent() { return 'Something went wrong!'; } } const myErrorMessage = new ErrorMessage();
Just one class / template: Message
const myTestMessage = new Message(); myTestMessage.setContent('Hello, I am a test message'); const myErrorMessage = new Message(); myErrorMessage.setContent('Something went wrong!');
console.log( myTestMessage.getContent() ); // Hello, I am a test message! console.log( myErrorMessage.getContent() ); // Something went wrong!
class Message { setContent(content) { this.content = content; } getContent() { return this.content; } }
const myMessage = new Message(); myMessage.setContent('Hello, I am a test message'); myMessage.content = 'Hello, I am a test message'; console.log( myMessage.getContent() ); console.log( myMessage.content );
class Message { set content(content) { this.content = content; } get content() { return this.content; } }
class Message { set content(content) { this.content = content; } }
This may make it easier to spot
class Message { setContent(content) { this.setContent(content); } }
Maximum call stack size exceeded
class Message { set content(content) { this.content = content; this._content = content; } get content() { return this.content; return this._content; } }
This seems like a lot of work... why bother?
You're right!
A regular object does getters and setters
const myMessage = new Object(); myMessage.content = 'Hello, I am a test message'; console.log( myMessage.content ); // Hello, I am a test message
class Message { // Empty }
const myMessage = new Message(); myMessage.content = 'Hello, I am a test message'; console.log( myMessage.content ); // Hello, I am a test message
Let's get clever with classes
class Message { set priority(priority) { if (priority < 1 || priority > 10) { throw new Error('Priority must be between 1 and 10'); } this._priority = priority; } }
const myMessage = new Message(); myMessage.priority = 20; // ERROR: Priority must be between 1 and 10 myMessage.priority = 5;
class Message { get log() { return `${this.timestamp} - [${this.priority}] ${this.content}`; } }
const myMessage = new Message(); myMessage.timestamp = new Date(); myMessage.priority = 5; myMessage.content = 'Hello, this is a test message'; console.log( myMessage.log ); // Mon Nov 16 2015 20:24:01 GMT+0000 (GMT) - [5] Hello, this is a test message
Wouldn't it be nice if timestamp was automatically set?
Special function named constructor
Automatically runs when the class is created
class Message { constructor() { this.timestamp = new Date(); } }
const myMessage = new Message(); console.log( myMessage.timestamp ); // Mon Nov 16 2015 20:24:01 GMT+0000 (GMT)
Construtors accept parameters too
class Message { constructor(content) { this.timestamp = new Date(); this.content = content; } }
const myTestMessage = new Message('Hello, this is a test message'); const myErrorMessage = new Message('Something went wrong!');
Allows a class to inherit everything from another class
class DebugMessage extends Message { // Empty } class ErrorMessage extends Message { // Empty }
const myDebugMessage = new DebugMessage('I am a debug message'); const myErrorMessage = new ErrorMessage('I am an error message');
Everything still works!
class Message { setContent(content) { this.content = content; } }
class ErrorMessage extends Message { setContent(content) { content = content + '!!!'; super.setContent(content); } }
const myMessage = new Message('I am a message'); console.log( myMessage.content ); // I am a message const myErrorMessage = new ErrorMessage('I am an error message'); console.log( myErrorMessage.content ); // I am an error message!!!
class Message { set content(content) { this._content = content; } }
class ErrorMessage extends Message { set content(content) { content = content + '!!!'; super.content = content } }
class Message { constructor(content) { this.content = content; this.priority = 5; } }
class DebugMessage extends Message { constructor(content) { super(content); this.priority = 1; } }
const myMessage = new Message('I am a message'); console.log( myMessage.priority ); // 5 const myDebugMessage = new DebugMessage('Just testing'); console.log( myErrorMessage.priority ); // 1
New syntax to easily create anonymous functions
// ES5 const debugMessages = messages.filter(function(message) { return message.priority === 1; });
// ES6 const debugMessages = messages.filter((message) => { return message.priority === 1; });
const debugMessages = messages.filter((message) => { return message.priority === 1; });
const debugMessages = messages.filter((message) => message.priority === 1);
const debugMessages = messages.filter(message => message.priority === 1);
// ES5 anonymous function function(param1, param2) { // ... }
// ES6 arrow function (param1, param2) => { // ... }
They look different... so what?
What's wrong with this code?
class Message { constructor() { this.priority = 5; } increasePriorityEverySecond() { setInterval(function() { this.priority = this.priority + 1; }, 1000); } }
What's wrong with this code?
class Message { constructor() { this.priority = 5; } increasePriorityEverySecond() { setInterval(function() { this.priority = this.priority + 1; }, 1000); } }
class Message { increasePriorityEverySecond() { var self = this; setInterval(function() { self.priority = self.priority + 1; }, 1000); } }
class Message { increasePriorityEverySecond() { setInterval(function() { this.priority = this.priority + 1; }.bind(this), 1000); } }
Arrow functions retain this from parent scope
class Message { increasePriorityEverySecond() { setInterval(() => { this.priority = this.priority + 1; }, 1000); } }
class Message { increasePriorityEverySecond() { setInterval(() => this.priority = this.priority + 1, 1000); } }
class Message { increasePriority() { this.priority = this.priority + 1 } increasePriorityEverySecond() { setInterval(() => this.increasePriority(), 1000); } }
// Globals var myModule = window.myModule; // AMD / RequireJS define(['myModule'], function(myModule) { }); // CommonJS / npm module.exports = myModule; var myModule = require('myModule'); // ES6 export myModule; import { myModule } from 'myModule';
// Globals var myModule = window.myModule; // AMD / RequireJS define(['myModule'], function(myModule) {}); // CommonJS / npm module.exports = myModule; var myModule = require('myModule'); // ES6 modules export myModule; import { myModule } from 'myModule';
// message.js export class Message { // ... }
// main.js import { Message } from './message.js'; const myMessage = new Message();
// message-utils.js export function displayMessage(message) { // ... } export function removeMessage(message) { // ... }
import { displayMessage, removeMessage } from './message-utils.js';
import { removeMessage } from './message-utils.js';
import * as MessageUtils from './message-utils.js'; MessageUtils.displayMessage(); MessageUtils.removeMessage();
// /vendor/message.js export class Message {}
// /app/message.js export class Message {}
import { Message as MessageVendor } from '/vendor/message.js'; import { Message as MessageApp } from '/app/message.js';
One per module
// message.js export default class Message {}
// main.js import NameItWhateverYouLike from './message.js'
ES6 only specifies a standard forthe import & export syntax
ES6 does not specify a standard for loading files
import { nope } from '../browser/does/not/know/how/to/load/this/file.js';
Solution
Use a bundling tool that understands ES6 modulestestInternetConnection(function() { fetchMessagesFromServer(function(messages) { messages = JSON.parse(messages); if (messages[0] === null) { displayError('Could not email first message'); logger.log('First message does not exist'); } else { sendEmail( 'test@example.com', 'Here is the first message: ' + messages[0], function() { displayMessage('Success!'); }, function(error) { displayError('Could not email first message'); logger.log('Error sending email: ' + error); } ); } }, function(error) { displayError('Could not email first message'); logger.log('Error fetching messages from server: ' + error); }); }, function(error) { displayError('Could not email first message'); logger.log('Internet connection test failed: ' + error); });
testInternetConnection({ onComplete: function() { fetchMessagesFromServer({ onComplete: function(messages) { messages = JSON.parse(messages); if (messages[0] === null) { displayError('Could not email first message'); logger.log('First message does not exist'); } else { sendEmail({ email: 'test@example.com', message: 'Here is the first message: ' + messages[0], onComplete: function() { displayMessage('Success!'); }, onError: function(error) { displayError('Could not email first message'); logger.log('Error sending email: ' + error); } }); } }, onError: function(error) { displayError('Could not email first message'); logger.log('Error fetching messages from server: ' + error); } }); }, onError: function(error) { displayError('Could not email first message'); logger.log('Internet connection test failed: ' + error); } });
testInternetConnection() .done(function() { fetchMessagesFromServer() .done(function(messages) { messages = JSON.parse(messages); if (messages[0] === null) { displayError('Could not email first message'); logger.log('First message does not exist'); } else { sendEmail({ email: 'test@example.com', message: 'Here is the first message: ' + messages[0] }) .done(function() { displayMessage('Success!'); }) .error(function(error) { displayError('Could not email first message'); logger.log('Error sending email: ' + error); }); } }) .error(function(error) { displayError('Could not email first message'); logger.log('Error fetching messages from server: ' + error); }); }) .error(function(error) { displayError('Could not email first message'); logger.log('Internet connection test failed: ' + error); });
testInternetConnection() .done(testInternetConnectionDone) .error(testInternetConnectionError); function testInternetConnectionDone() { fetchMessagesFromServer() .done(fetchMessagesFromServerDone) .error(fetchMessagesFromServerError) } function testInternetConnectionError(error) { displayError('Could not email first message'); logger.log('Internet connection test failed: ' + error); } function fetchMessagesFromServerDone(messages) { messages = JSON.parse(messages); if (messages[0] === null) { displayError('Could not email first message'); logger.log('First message does not exist'); } else { sendEmail({ email: 'test@example.com', message: 'Here is the first message: ' + messages[0] }) .done(sendEmailDone) .error(sendEmailError); } } function fetchMessagesFromServerDoneError() { displayError('Could not email first message'); logger.log('Error fetching messages from server: ' + error); } function sendEmailDone() { displayMessage('Success!'); } function sendEmailError(error) { displayError('Could not email first message'); logger.log('Error sending email: ' + error); }
function fetchMessagesFromServer() { // This function takes time // Return to caller a Promise object straight away return new Promise(function(resolve, reject) { // After some time has passed, update the Promise // Two types of updates; // 1. Resolve (yay) with a value // 2. Reject (aw) with a value jQuery.get('http://example.com/messages.json') // time passes .done(function(result) { // Update the Promise // Resolve, and pass in the result resolve(result); }) .fail(function() { // Update the Promise // Reject, and pass in an error message reject('Could not fetch messages from server'); }); }); }
const messages = fetchMessagesFromServer(); console.log( messages ); // Promise - what do I do with this?!
fetchMessagesFromServer() .then(function(value) { // Promise resolved console.log(value); }) .catch(function(value) { // Promise rejected console.log(value); });
So what?
fetchMessagesFromServer() .then(function(messages) { // ... }) .catch(function(error) { // ... });
fetchMessagesFromServer( function(messages) { // ... }, function(error) { // ... } );
fetchMessagesFromServer({ onComplete: function(messages) { // ... }, onError: function(error) { // ... } });
fetchMessagesFromServer() .done(function(messages) { // ... }) .fail(function(error) { // ... });
The power of Promises:
Chaining them together
The function within then() can do 3 types of things;
1. Return another promise
fetchMessagesFromServer() .then(function(messages) { const promise = sendEmail('test@example.com', messages); return promise; }) .then(function(email) { // ... }) .catch(function(error) { // ... });
The function within then() can do 3 types of things;
2. Return a value
fetchMessagesFromServer() .then(function(messages) { return messages[0]; }) .then(function(firstMessage) { // ... });
This is the same as resolving a Promise
The function within then() can do 3 types of things;
3. Throw an error
fetchMessagesFromServer() .then(function(messages) { // Try to do something a little crazy throw new Error('Uh oh'); }) .catch(function(error) { // ... });
This is the same as rejecting a Promise
testInternetConnection() .then(function() { return fetchMessagesFromServer(); }) .then(function(messages) { return JSON.parse(messages); }) .then(function(messages) { if (messages[0] === null) { throw new Error('First message does not exist'); } else { return messages[0]; } }) .then(function(firstMessage)) { return sendEmail( 'test@example.com', 'Here is the first message: ' + firstMessage ); }) .then(function() { displayMessage('Success!'); }) .catch(function(error) { displayError('Could not email first messsage'); logger.log(error); });
class MessageService { fetchMessagesAsJson() { return testInternetConnection() .then(fetchMessagesFromServer) .then(JSON.parse); } } class MessageEmailer { _getFirstMessage(messages) { if (messages[0] === null) { throw new Error('First message does not exist'); } return messages[0]; } _emailMessage(email, message) { return sendEmail(email, 'Here is the message: ' + message); } send(email) { MessageService.fetchMessagesAsJson() .then(this._getFirstMessage) .then(firstMessage => this._emailMessage(email, firstMessage)) .then(() => displayMessage('Success!')) .catch((error) => { displayError('Could not email message'); console.log(error); }) } }
Yes, there are more...
http://github.com/turnbullm/js-2015-preso
Summary github.com/lukehoban/es6features Detail es6-features.org 350 bullet points ponyfoo.com/articles/es6 Interactive lessons learnharmony.org TDD style lessons es6katas.org Reference developer.mozilla.orgFinal message...
Do it for Barry