├── .gitignore ├── README.md ├── index.html ├── package.json ├── src ├── Point.js ├── arbitraryArguments.js ├── arrow.js ├── async.js ├── classes.js ├── defaultParameters.js ├── destructuring.js ├── exports.js ├── forEach.js ├── functionExpression.js ├── generators.js ├── iife.js ├── imports.js ├── letConst.js ├── main.js ├── maps.js ├── multipleReturnValues.js ├── namedParameters.js ├── optionalNamedParameters.js ├── promises.js ├── sets.js ├── spread.js ├── stringInterpolation.js ├── strings.js ├── sumOfSquares.js └── symbols.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/* 2 | bundle.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # es6-deep-dive 2 | 3 | Repository containing examples highlighting differences and improvements between ES5 and ES6. 4 | 5 | # Running examples 6 | 7 | To run the examples contained in this repository: 8 | 9 | # Install the dependencies 10 | npm install 11 | 12 | # Run Webpack 13 | npm run watch 14 | 15 | Note: For OS X users, you'll have to prepend `sudo` to the above commands. 16 | 17 | Once Webpack is running, simply open `index.html`. 18 | 19 | # LICENSE 20 | 21 | The MIT License (MIT) 22 | 23 | Copyright (c) 2015 David Leonard 24 | 25 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 26 | 27 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webpack ES6 Demo 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es6-deep-dive", 3 | "version": "0.0.1", 4 | "description": "ES5 -> ES6 Deep Dive", 5 | "main": "main.js", 6 | "devDependencies": { 7 | "babel-core": "*", 8 | "babel-loader": "*", 9 | "node-libs-browser": "*", 10 | "webpack": "*" 11 | }, 12 | "scripts": { 13 | "watch": "webpack --watch" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/DrkSephy/es6-deep-dive.git" 18 | }, 19 | "keywords": [ 20 | "es5", 21 | "es6", 22 | "webpack" 23 | ], 24 | "author": "David Leonard", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/DrkSephy/es6-deep-dive/issues" 28 | }, 29 | "homepage": "https://github.com/DrkSephy/es6-deep-dive", 30 | "dependencies": { 31 | "babel-preset-es2015": "^6.16.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Point.js: -------------------------------------------------------------------------------- 1 | class Point { 2 | 3 | constructor(x, y, z) { 4 | this.x = x; 5 | this.y = y; 6 | this.z = z; 7 | } 8 | 9 | toString() { 10 | return ' (' + this.x + ' , ' + this.y + ' , ' + this.z + ')'; 11 | } 12 | } 13 | export default Point; -------------------------------------------------------------------------------- /src/arbitraryArguments.js: -------------------------------------------------------------------------------- 1 | // Arbitrary amount of arguments using ES5 2 | function logAllArguments() { 3 | for (var i=0; i < arguments.length; i++) { 4 | console.log(arguments[i]); 5 | } 6 | } 7 | 8 | // In ES6, we can use a rest parameter to specify an 9 | // arbitrary amount of arguments 10 | function logAllArguments(...args) { 11 | for (let arg of args) { 12 | console.log(arg); 13 | } 14 | } -------------------------------------------------------------------------------- /src/arrow.js: -------------------------------------------------------------------------------- 1 | // ES5 2 | // Trying to prefix this.name from Person won't work due to the scoping 3 | // and the value of this being changed 4 | 5 | function Person(name) { 6 | this.name = name; 7 | } 8 | 9 | Person.prototype.prefixName = function (arr) { 10 | return arr.map(function (character) { 11 | return this.name + character; 12 | }); 13 | }; 14 | 15 | // ES5 Solution 1: Store the this pointer 16 | 17 | function Person(name) { 18 | this.name = name; 19 | } 20 | 21 | Person.prototype.prefixName = function (arr) { 22 | var that = this; 23 | return arr.map(function (character) { 24 | return that.name + character; 25 | }); 26 | }; 27 | 28 | // ES5 Solution 2: Pass the value that this should be 29 | // when the callback is invoked 30 | 31 | function Person(name) { 32 | this.name = name; 33 | } 34 | 35 | Person.prototype.prefixName = function (arr) { 36 | return arr.map(function (character) { 37 | return this.name + character; 38 | }, this); 39 | } 40 | 41 | // ES5 Solution 3: Bind the correct value of this 42 | function Person(name) { 43 | this.name = name; 44 | } 45 | 46 | Person.prototype.prefixName = function (arr) { 47 | return arr.map(function (character) { 48 | return this.name + character; 49 | }.bind(this)); 50 | } 51 | 52 | // ES6 Solution: Use the Arrow function! 53 | function Person(name) { 54 | this.name = name; 55 | } 56 | 57 | Person.prototype.prefixName = function(arr) { 58 | return arr.map((character) => { 59 | return this.name + character; 60 | }); 61 | }; 62 | 63 | // ES6 Function Expressions versus arrow functions 64 | const arr = [1, 2, 3, 4, 5]; 65 | const squares = arr.map(x => x * x); 66 | 67 | // Traditional function expression: 68 | const squares = arr.map(function (x) { return x * x }); -------------------------------------------------------------------------------- /src/async.js: -------------------------------------------------------------------------------- 1 | // Explaining ES7 Async await 2 | 3 | var request = require('request'); 4 | 5 | function getJSON(url) { 6 | 7 | request(url, function(error, response, body) { 8 | return body; 9 | }); 10 | } 11 | 12 | function main() { 13 | var data = getJSON('http://some_api/item1'); 14 | console.log(data); // Undefined 15 | } 16 | 17 | main(); 18 | 19 | // Solution? Async/await 20 | var request = require('request'); 21 | 22 | function getJSON(url) { 23 | return new Promise(function(resolve, reject) { 24 | request(url, function(error, response, body) { 25 | resolve(body); 26 | }); 27 | }); 28 | } 29 | 30 | async function main() { 31 | var data = await getJSON(); 32 | console.log(data); // NOT undefined! 33 | } 34 | 35 | main(); 36 | 37 | -------------------------------------------------------------------------------- /src/classes.js: -------------------------------------------------------------------------------- 1 | // ES6 example of a class 2 | 3 | // ES5 Base Class 4 | function Person(name, age, gender) { 5 | this.name = name; 6 | this.age = age; 7 | this.gender = gender; 8 | } 9 | 10 | Person.prototype.incrementAge = function () { 11 | return this.age += 1; 12 | }; 13 | 14 | // Base class 15 | class Person { 16 | constructor(name, age, gender) { 17 | this.name = name; 18 | this.age = age; 19 | this.gender = gender; 20 | } 21 | 22 | incrementAge() { 23 | this.age += 1; 24 | } 25 | } 26 | 27 | // Extended Classes in ES5 28 | function Employee(name, title) { 29 | Person.call(this, name); // super(name) 30 | this.title = title; 31 | } 32 | Employee.prototype = Object.create(Person.prototype); 33 | Employee.prototype.constructor = Employee; 34 | Employee.prototype.describe = function () { 35 | return Person.prototype.describe.call(this) // super.describe() 36 | + ' (' + this.title + ')'; 37 | }; 38 | 39 | function Personal(name, age, gender, occupation, hobby) { 40 | Person.call(this, name, age, gender); 41 | this.occupation = occupation; 42 | this.hobby = hobby; 43 | } 44 | 45 | Personal.prototype = Object.create(Person.prototype); 46 | Personal.prototype.constructor = Personal; 47 | Personal.prototype.incrementAge = function () { 48 | return Person.prototype.incrementAge.call(this) += 1; 49 | } 50 | 51 | // Extended Class 52 | class Personal extends Person { 53 | constructor(name, age, gender, occupation, hobby) { 54 | super(name, age, gender); 55 | this.occupation = occupation; 56 | this.hobby = hobby; 57 | } 58 | 59 | incrementAge() { 60 | super.incrementAge(); 61 | this.age += 20; 62 | console.log(this.age); 63 | } 64 | } 65 | 66 | const person = new Personal('David', 25, 'male', 'metalhead', 'game development'); 67 | person.incrementAge(); 68 | 69 | 70 | let _counter = new WeakMap(); 71 | let _action = new WeakMap(); 72 | class Countdown { 73 | constructor(counter, action) { 74 | _counter.set(this, counter); 75 | _action.set(this, action); 76 | } 77 | dec() { 78 | let counter = _counter.get(this); 79 | if (counter < 1) return; 80 | counter--; 81 | _counter.set(this, counter); 82 | if (counter === 0) { 83 | _action.get(this)(); 84 | } 85 | } 86 | } 87 | 88 | // Simulating private data using WeakMaps 89 | let _age = new WeakMap(); 90 | class Person { 91 | constructor(age) { 92 | _age.set(this, age); 93 | } 94 | 95 | incrementAge() { 96 | let age = _age.get(this); 97 | if(age > 50) { 98 | console.log('Midlife crisis'); 99 | } 100 | } 101 | } 102 | 103 | > const person = new Person(25); 104 | > person.incrementAge(); 105 | > Reflect.ownKeys(person); // [] -------------------------------------------------------------------------------- /src/defaultParameters.js: -------------------------------------------------------------------------------- 1 | // Handling default parameters in ES5 2 | function addTwoNumbers(x, y) { 3 | x = x || 0; 4 | y = y || 0; 5 | return x + y; 6 | } 7 | 8 | // Handling default parameters in ES6 9 | function addTwoNumbers(x=0, y=0) { 10 | return x + y; 11 | } 12 | 13 | addTwoNumbers(2, 4); // 6 14 | addTwoNumbers(2); // 2 15 | addTwoNumbers(); // 0 -------------------------------------------------------------------------------- /src/destructuring.js: -------------------------------------------------------------------------------- 1 | // Destructuring allows us to bind properties to as many variables 2 | // as we need. 3 | 4 | // Example for Objects 5 | var luke = { occupation: 'jedi', father: 'anakin' } 6 | var {occupation, father} = luke; 7 | console.log(occupation); // 'jedi' 8 | console.log(father); // 'anakin' 9 | 10 | // Example for Arrays 11 | var [a] = [10] 12 | console.log(a); // 10 13 | 14 | // Using Destructuring to interact with objects easier 15 | function getCoords () { 16 | return { 17 | x: 10, 18 | y: 22 19 | } 20 | } 21 | 22 | var {x, y} = getCoords() 23 | console.log(x); // 10 24 | // <- 10 25 | console.log(y); // 22 26 | -------------------------------------------------------------------------------- /src/exports.js: -------------------------------------------------------------------------------- 1 | // CommonJS exports in ES5 2 | module.exports = 1 3 | module.exports = { foo: 'bar' } 4 | module.exports = ['foo', 'bar'] 5 | module.exports = function bar () {} 6 | 7 | // Exports in ES6 8 | export default 1 9 | export default { foo: 'bar' } 10 | export default ['foo', 'bar'] 11 | export default function bar () {} 12 | 13 | // Named Exports in CommonJS 14 | module.exports.name = 'David'; 15 | module.exports.age = 25; 16 | 17 | // Named Exports in ES6 18 | // NOTE: Exports are binding, changing the variable used when 19 | // imported would affect the public interface itself 20 | export var name = 'David'; 21 | export var age = 25; 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/forEach.js: -------------------------------------------------------------------------------- 1 | // Array iteration using forEach in ES5 2 | arr.forEach(function (item) { 3 | console.log(item); 4 | }); 5 | 6 | // Iterate over an array using ES6 7 | let arr = ['a', 'b', 'c']; 8 | for (let item of arr) { 9 | console.log(item); 10 | } 11 | 12 | // Get both index and value using .entries and destructuring 13 | for (let [index, item] of arr.entries()) { 14 | console.log(index+'. '+item); 15 | } -------------------------------------------------------------------------------- /src/functionExpression.js: -------------------------------------------------------------------------------- 1 | function Component { 2 | var _this = this; // Copy instance of this pointer 3 | var button = document.getElementById('myButton'); 4 | button.addEventListener('click', function () { 5 | console.log('CLICK'); 6 | _this.handleClick(); // Inner instance of this 7 | }); 8 | } 9 | 10 | // Extend prototype with handleClick function 11 | UiComponent.prototype.handleClick = function () { 12 | ··· 13 | }; 14 | 15 | // Arrow functions don't shadow (this), which is lexical to current scope 16 | class Component { 17 | constructor() { 18 | let button = document.getElementById('myButton'); 19 | button.addEventListener('click', () => { 20 | console.log('CLICK'); 21 | this.handleClick(); // Fat arrow handles this for us 22 | }); 23 | } 24 | 25 | // extend Component class with handleClick function 26 | handleClick() { 27 | ··· 28 | } 29 | } -------------------------------------------------------------------------------- /src/generators.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Notes on ES6 Generators. 3 | */ 4 | 5 | function* sillyGenerator() { 6 | yield 1; 7 | yield 2; 8 | yield 3; 9 | yield 4; 10 | } 11 | 12 | var generator = sillyGenerator(); 13 | var value = generator.next(); 14 | > console.log(value); // { value: 1, done: false } 15 | > console.log(value); // { value: 2, done: false } 16 | > console.log(value); // { value: 3, done: false } 17 | > console.log(value); // { value: 4, done: false } 18 | 19 | // Note how the generator is technically not done iterating 20 | // It will return { value: undefined, done: true} on next 21 | // iteration. 22 | 23 | // Can we use return? Using for...of 24 | function* sillyGenerator() { 25 | yield 1; 26 | yield 2; 27 | yield 3; 28 | yield 4; 29 | return 5; 30 | } 31 | 32 | for(let val of sillyGenerator()) { 33 | console.log(val); // 1, 2, 3, 4 34 | } 35 | 36 | // We'll never get 5, since we exposed no method to use .next() 37 | 38 | 39 | // Actual generator example 40 | function* factorial(){ 41 | let [current, total] = [0, 1]; 42 | 43 | while (true){ 44 | 45 | yield total; 46 | 47 | current++; 48 | total = total * current; 49 | } 50 | } 51 | 52 | for (let n of factorial()) { 53 | console.log(n); 54 | if(n >= 100000) { 55 | break; 56 | } 57 | } 58 | 59 | // Hiding asynchronousity with Generators 60 | function request(url) { 61 | getJSON(url, function(response) { 62 | generator.next(response); 63 | }); 64 | } 65 | 66 | function* getData() { 67 | var entry1 = yield request('http://some_api/item1'); 68 | var data1 = JSON.parse(entry1); 69 | var entry2 = yield request('http://some_api/item2'); 70 | var data2 = JSON.parse(entry2); 71 | } 72 | 73 | // Upgrading our generator using promises 74 | function request(url) { 75 | // Note: returning a promise now! 76 | return new Promise( function(resolve,reject){ 77 | makeAjaxCall( url, resolve ); 78 | } ); 79 | } 80 | 81 | // This will yield a promise 82 | function request(url) { 83 | return new Promise((resolve, reject) => { 84 | getJSON(url, resolve); 85 | }); 86 | } 87 | 88 | // Construct a function to control the generator 89 | function iterateGenerator(gen) { 90 | var generator = gen(); 91 | var ret; 92 | (function iterate(val) { 93 | ret = generator.next(); 94 | if(!ret.done) { 95 | ret.value.then(iterate); 96 | } else { 97 | setTimeout(function() { 98 | iterate(ret.value); 99 | }); 100 | } 101 | })(); 102 | } 103 | 104 | iterateGenerator(function* getData() { 105 | var entry1 = yield request('http://some_api/item1'); 106 | var data1 = JSON.parse(entry1); 107 | var entry2 = yield request('http://some_api/item2'); 108 | var data2 = JSON.parse(entry2); 109 | }); 110 | 111 | -------------------------------------------------------------------------------- /src/iife.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var temp = 10; 3 | }()); 4 | 5 | console.log(temp); // Error, temp is not defined 6 | 7 | // Instead of using IIFE inside of ES5, 8 | // Simply use blocks in ES6 9 | { // open block 10 | let temp = 10; 11 | } // close block 12 | 13 | console.log(temp); // ReferenceError -------------------------------------------------------------------------------- /src/imports.js: -------------------------------------------------------------------------------- 1 | // main.js 2 | import { sumTwo, sumThree } from 'math/addition'; 3 | 4 | // Alternate way to import by providing aliases 5 | import { 6 | sumTwo as addTwoNumbers, 7 | sumThree as addThreeNumbers 8 | } from 'math/addition'; 9 | 10 | import * as addition from 'math/addition'; 11 | 12 | console.log(sumTwo(2, 3)); 13 | 14 | // Alternate calls (1) 15 | console.log(addTwoNumbers(2, 3)); 16 | 17 | // Alternate calls (2) 18 | console.log(addition.sumTwo(2, 3)); 19 | 20 | /////////////////////////////////////////////////// 21 | 22 | // math/addition.js 23 | function sumTwo(a, b) { 24 | return a + b; 25 | } 26 | 27 | function sumThree(a, b) { 28 | return a + b + c; 29 | } 30 | 31 | export { sumTwo, sumThree }; 32 | 33 | // Alternate expoorts 34 | 35 | function sumTwo(a, b) { 36 | return a + b; 37 | } 38 | 39 | function sumThree(a, b) { 40 | return a + b + c; 41 | } 42 | 43 | var api = { 44 | sumTwo : sumTwo, 45 | sumThree: sumThree 46 | } 47 | 48 | export default api -------------------------------------------------------------------------------- /src/letConst.js: -------------------------------------------------------------------------------- 1 | // ES5 2 | 3 | var snack = 'Meow Mix'; 4 | 5 | function getFood(food) { 6 | if (food) { 7 | var snack = 'Friskies'; 8 | return snack; 9 | } 10 | return snack; 11 | } 12 | 13 | getFood(false); // Undefined 14 | 15 | // Re-write the above example 16 | var snack = 'Meow Mix'; 17 | 18 | function getFood(food) { 19 | 20 | var snack; // Hoisting 21 | 22 | if (food) { 23 | snack = 'Friskies'; 24 | return snack; 25 | } 26 | 27 | return snack; 28 | } 29 | 30 | getFood(false); // Undefined 31 | 32 | // ES6 33 | 34 | let snack = 'Meow Mix'; 35 | 36 | function getFood(food) { 37 | 38 | if (food) { 39 | let snack = 'Friskies'; 40 | return snack; 41 | } 42 | 43 | return snack; 44 | } 45 | 46 | getFood(false); -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Point from './Point.js'; 2 | var body = document.querySelector('body'); 3 | body.textContent = 'Good point: ' + new Point(1, 23, 99); -------------------------------------------------------------------------------- /src/maps.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Maps are a new Data Structure in JavaScript. 3 | * They allow us to use arbitrary values as keys. 4 | * Not just strings, as we used hash maps for. 5 | */ 6 | 7 | // Hash maps in ES5 8 | var map = new Object(); 9 | map[key1] = 'value1'; 10 | map[key2] = 'value2'; 11 | 12 | // Problem 1 13 | // How do we get our own properties of an object? 14 | function getOwnProperty(object, propertyKey) { 15 | return (object.hasOwnProperty(propertyKey) ? object[propertyKey]: undefined); 16 | } 17 | 18 | // However...what if we overwrite the property hasOwnProperty? 19 | > getOwnProperty({ hasOwnProperty: 'Hah, overwritten'}, 'Pwned'); 20 | > TypeError: Propery 'hasOwnProperty' is not a function 21 | 22 | // How to fix? 23 | function getOwnProperty(object, propertyKey) { 24 | return (Object.prototype.hasOwnProperty(object, propertyKey) ? object[propertyKey]: undefined); 25 | } 26 | 27 | // ^ Abuse of an object to create a hash map 28 | 29 | // Actual Maps in ES6 30 | let map = new Map(); 31 | > map.set('name', 'david'); 32 | > map.get('name'); // david 33 | > map.has('name'); // true 34 | 35 | // Keys in Maps can be more than a string 36 | let map = new Map(); 37 | 38 | const KEY = {}; // We can use objects! 39 | > map.set(KEY, 'ES6 for the win'); 40 | > map.get((KEY)); // 'ES6 for the win' 41 | 42 | // Iterating over a Map 43 | let map = new Map([ 44 | ['name', 'david'], 45 | [true, 'false'], 46 | [1, 'one'], 47 | [{}, 'object'], 48 | [function () {}, 'function'] 49 | ]); 50 | 51 | for (let key of map.keys()) { 52 | console.log(typeof key); 53 | // > string, boolean, number, object, function 54 | }; 55 | 56 | // .entries() 57 | for (let entry of map.entries()) { 58 | console.log(entry[0], entry[1]); 59 | } 60 | 61 | // More convenient syntax using destructuring: 62 | for (let [key, value] of map.entries()) { 63 | console.log(key, value); 64 | } 65 | -------------------------------------------------------------------------------- /src/multipleReturnValues.js: -------------------------------------------------------------------------------- 1 | // Object.getOwnPropertyDescriptor returns property descriptors, 2 | // which is an object that holds multiple values in it's properties. 3 | 4 | // When using ES5, note that we still need an intermediate variable 5 | // In this case, it's propDesc 6 | var obj = { bar: '123' }; 7 | 8 | var propDesc = Object.getOwnPropertyDescriptor(obj, 'bar'); 9 | var writable = propDesc.writable; 10 | var configurable = propDesc.configurable; 11 | 12 | console.log(writable, configurable); // true true 13 | 14 | // Using ES6, we can return multiple values without using intermediate variables 15 | // through the use of destructuring 16 | let obj = { bar: '123' }; 17 | 18 | let {writable, configurable} = 19 | Object.getOwnPropertyDescriptor(obj, 'bar'); 20 | 21 | console.log(writable, configurable); // true true 22 | 23 | // {writeable, configurable} is equivalent to {writable: writable, configurable: configurable} 24 | -------------------------------------------------------------------------------- /src/namedParameters.js: -------------------------------------------------------------------------------- 1 | // Example of options object pattern in ES5 for 2 | // handling named parameters 3 | function selectEntries(options) { 4 | var start = options.start || 0; 5 | var end = options.end || -1; 6 | var step = options.step || 1; 7 | } 8 | 9 | // Once again, destructuring to the rescue. We can pass in an object 10 | // as a function parameter in ES6 to handle named parameters. 11 | function selectEntries({ start=0, end=-1, step=1 }) { 12 | // Code here 13 | } 14 | 15 | function initializeCanvas(options) { 16 | var height = options.height || 600; 17 | var width = options.width || 400; 18 | var lineStroke = options.lineStroke || 'black'; 19 | } 20 | 21 | function initializeCanvas({ height=600, width=400, lineStroke='black'}) { 22 | ... 23 | } -------------------------------------------------------------------------------- /src/optionalNamedParameters.js: -------------------------------------------------------------------------------- 1 | // Make parameter options optional in ES5 2 | function selectEntries(options) { 3 | options = options || {}; // optional parameter 4 | var start = options.start || 0; 5 | var end = options.end || -1; 6 | var step = options.step || 1; 7 | } 8 | 9 | // In ES6, we can make the parameter optional by = {} 10 | function selectEntries({ start=0, end=-1, step=1 } = {}) { 11 | 12 | } -------------------------------------------------------------------------------- /src/promises.js: -------------------------------------------------------------------------------- 1 | /* What are promises? 2 | * 3 | * Promises are basically placeholders for values that will eventually exist. 4 | * They make it easier to reason about code, and are a nice substitute for callbacks. 5 | */ 6 | 7 | // Promise allow us to turn our horizontal code: 8 | func1(function (value1) { 9 | func2(value1, function(value2) { 10 | func3(value2, function(value3) { 11 | func4(value3, function(value4) { 12 | func5(value4, function(value5) { 13 | // Do something with value 5 14 | }); 15 | }); 16 | }); 17 | }); 18 | }); 19 | 20 | // Into... 21 | func1(value1) 22 | .then(func2(value1) { }) 23 | .then(func3(value2) { }) 24 | .then(func4(value3) { }) 25 | .then(func5(value4) { 26 | // Do something with value 5 27 | }) 28 | 29 | var data = requests.get('http://swapi.co/api/people/1'); // .get returns a brand new data promises 30 | var response = data.then(res => res.body); // data.then returns another new promise 31 | var save = response.catch(err => console.error(err)); // response.catch returns another new promise 32 | 33 | // requests.get returns a brand new data promise 34 | // data.then returns another new promise 35 | // response.catch returns another new promise 36 | // When data is (fufilled), data.then reaction is executed 37 | // response is then settled who was waiting for data.then to settled 38 | // response was rejected, so we run a .catch instead of .then branch 39 | // save is fufilled and logs the error 40 | 41 | // In ES6, we no longer need libraries to create Promises. We can create them 42 | // from scratch. 43 | 44 | // new Promise(resolve => resolve()) // promise was fufilled 45 | // new Promise((resolve, reject) => reject()) // promise was rejected 46 | 47 | new Promise(resolve => resolve(data)) 48 | .then(result => console.log(data)); 49 | 50 | 51 | new Promise((resolve, reject) => 52 | reject(new Error('Failed to fufill Promise'))) 53 | .catch(reason => console.log(reason)); 54 | 55 | 56 | // Example of a promise 57 | var promise = new Promise(function(resolve, reject) { 58 | if (/* condition */) { 59 | resolve(/* value */); // fulfilled successfully 60 | } 61 | else { 62 | reject(/* reason */); // error, rejected 63 | } 64 | }); 65 | 66 | // The first handler (resolve) is called when the Promise has been fufilled, 67 | // and the value has been passed to the handler. 68 | 69 | // The second handler (reject) is called when the Promise has been rejected 70 | // with the value being passed to that handler. 71 | 72 | // A Promise can only be settled (fufilled/rejected) once, and this value is immutable. 73 | 74 | // Talk about concurrent promises using Promises.all 75 | 76 | // Promises in summary: 77 | // * Promises allow us to write asynchronous code in a synchronous matter 78 | // * Promises allow us to unify asynchronous APIS 79 | // * Promises guarantees no race conditions and immutability of the future value 80 | // represented by the promise 81 | 82 | // Promise example using getJson, to highlight multiple promises 83 | var fetchJSON = function(url) { 84 | return new Promise((resolve, reject) => { 85 | $.getJSON(url) 86 | .done((json) => resolve(json)) 87 | .fail((xhr, status, err) => reject(status + err.message)); 88 | }); 89 | } 90 | 91 | var urls = { 92 | 'http://www.api.com/items/1234', 93 | 'http://www.api.com/items/4567' 94 | }; 95 | 96 | var urlPromises = urls.map(fetchJSON); 97 | 98 | Promise.all(urlPromises) 99 | .then(function(results) { 100 | // If all the promises are fufilled, 101 | // we now execute this 102 | results.forEach(function(data) { 103 | // process our data 104 | }); 105 | }) 106 | .catch(function(err) { 107 | // Will catch failure of first failed promise 108 | console.log("Failed:", err); 109 | }); 110 | 111 | -------------------------------------------------------------------------------- /src/sets.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Sets are a new data structure in ES6. 3 | * Contains unique elements, is faster and handles NaN 4 | * The reason for this is that storing arbitrary 5 | * elements in an array (ES5) means we need to write 6 | * filter methods. Also, indexOf cannot handle NaN. 7 | */ 8 | 9 | let set = new Set(); 10 | > set.add('javascript'); 11 | > set.has('javascript'); // true 12 | > set.delete('javascript'); 13 | > set.has('javascript'); // false 14 | 15 | // Mapping a set 16 | let set = new Set([1, 2, 3, 4, 5]); 17 | set = new Set([...set].map(val => val * 2)); 18 | console.log(set); // {2, 4, 6, 8, 10} 19 | 20 | // Filtering a set 21 | let set = new Set([1, 2, 3, 4, 5]); 22 | set = new Set([...set].filter(val => val % 2)); 23 | console.log(set); // {2, 4} -------------------------------------------------------------------------------- /src/spread.js: -------------------------------------------------------------------------------- 1 | // Concatenating an array of strings using ES5 2 | function concat () { 3 | return Array.prototype.slice.call(arguments).join(' ') 4 | } 5 | 6 | var result = concat('The', 'cat', 'went', 'meow'); 7 | console.log(result); // 'The cat went meow' 8 | 9 | // Concatenating an array of strings using ES6 10 | function concat(...params) { 11 | return params.join(' '); 12 | } 13 | 14 | var result = concat('The', 'cat', 'went', 'meow'); 15 | console.log(result); // 'The cat went meow' 16 | 17 | const phrasesOne = ['The', 'cat']; 18 | const phrasesTwo = ['went', 'meow']; 19 | 20 | phrasesOne.push(...phrasesTwo); 21 | // phrasesOne = ['The', 'cat', 'went', 'meow'] 22 | -------------------------------------------------------------------------------- /src/stringInterpolation.js: -------------------------------------------------------------------------------- 1 | // String Interpolation in ES5 2 | function printCoord(x, y) { 3 | console.log('('+x+', '+y+')'); 4 | } 5 | 6 | // String interperation in ES6 using template literals 7 | function printCoord(x, y) { 8 | console.log(`(${x}, ${y})`); 9 | } -------------------------------------------------------------------------------- /src/strings.js: -------------------------------------------------------------------------------- 1 | // ES5 2 | 3 | var string = 'food'; 4 | 5 | var substring = 'foo'; 6 | 7 | // Check if substring is contained in string 8 | console.log(string.indexOf(substring) > -1); 9 | 10 | // ES6 11 | 12 | const string = 'food'; 13 | 14 | const substring = 'foo'; 15 | 16 | // Check if substring is contained in string 17 | console.log(string.includes(substring)); // true 18 | 19 | -------------------------------------------------------------------------------- /src/sumOfSquares.js: -------------------------------------------------------------------------------- 1 | // Return sum of squares of arr 2 | var arr = [1, 2, 3]; 3 | var squares = arr.map(function (x) { 4 | return x * x 5 | }); 6 | 7 | // Using the arrow function, we have a more concise solution. 8 | // Arrow functions are extremely useful to replace callbacks 9 | // which simply return the result of an expression. 10 | let arr = [1, 2, 3]; 11 | let squares = arr.map(x => x * x); -------------------------------------------------------------------------------- /src/symbols.js: -------------------------------------------------------------------------------- 1 | /* Symbols are a new primitive type useful for: 2 | * 1. Unique Property Keys 3 | * 2. Constants that represent a concept 4 | */ 5 | 6 | // Symbols used as Property Keys 7 | const key = Symbol(); 8 | const keyTwo = Symbol(); 9 | const object = {}; 10 | 11 | object.key = 'Such magic.'; 12 | object.keyTwo = 'Much Uniqueness' 13 | console.log(object.key); 14 | console.log(object.keyTwo); 15 | 16 | // Symbols are always Unique 17 | console.log(key === keyTwo); 18 | 19 | // Symbols are good for representing concepts 20 | const anakin = 'jedi'; 21 | const yoda = 'jedi master'; 22 | const luke = 'jedi'; 23 | 24 | // Now the value of 'jedi' is not Unique. Fix this with Symbols 25 | const anakin = Symbol(); 26 | const yoda = Symbol(); 27 | const luke = Symbol(); 28 | 29 | // Now values cannot be confused 30 | // Symbols are similar to strings, as they can represent 31 | // concepts and properties. On the other hand, they also 32 | // exhibit functionality of an object, as each symbol has 33 | // its own identity. -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | 3 | module.exports = { 4 | entry: './src/main.js', 5 | output: { 6 | path: __dirname, 7 | filename: 'bundle.js' 8 | }, 9 | module: { 10 | loaders: [ 11 | { 12 | test: /\.js/, 13 | loader: 'babel-loader', 14 | query: { 15 | presets: ['es2015'] 16 | } 17 | } 18 | ] 19 | } 20 | }; --------------------------------------------------------------------------------