by Rob Richardson
Rob Richardson is a software craftsman building web properties in ASP.NET and Node, Angular and Vue. He's a frequent speaker at conferences, user groups, and community events, and a diligent teacher and student of high quality software development. You can find this and other talks on https://robrich.org/presentations and follow him on twitter at @rob_rich.
JavaScript Harmony
EcmaScript 6
EcmaScript 2015
ES6
... they're the same thing
| Version | Date | Features |
| 1 | 6/1997 | |
| 2 | 6/1998 | |
| 3 | 12/1999 | |
| 4 | Abandoned | |
| 5 | 12/2009 | strict mode, JSON, standards |
| 5.1 | 6/2011 | standards |
| 6 | 6/2015 | classes, modules, iterators, generators, arrow functions, typed arrays, collections, promises, let, const, Array methods, etc |
| 7 | 6/2016 | **, Array#includes |
| 8 | 6/2017 | async / await |
| 9 | 6/2018 | rest, spread, async loops |
source: wikipedia.org/wiki/ECMAScript
... in the browser
The server-side ES story is interesting too,
but we'll focus on the browser story
Two main groups of new things:
Yes but ...
Browser support:
kangax.github.io/compat-table/es6/
www.caniuse.com
spoiler: Evergreen browsers will always lag, but you can "transpile" to older standards and use new things today
Transpiling is a specific term for taking source code written in one language and transforming into another language that has a similar level of abstraction.
Source: https://www.stevefenton.co.uk/2012/11/compiling-vs-transpiling/
Can I polyfill the feature?
HTML5 examples:
Yes: html5shiv adds Array methods and additional tags
No: Can't polyfill canvas tag
Using Babel
Using Babel
Using Webpacknpm install --save-dev webpack-cli
npm install --save-dev webpack
webpack main.js -o bundle.js
Then reference bundle.js from your html
Using Webpackwebpack.config.js:
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
$> webpack
webpack.config.js:
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
};
.babelrc:
...
webpack.config.js:
...
.babelrc:
{
"presets": ["@babel/preset-env"]
}
Then run these from the command line
npm install --save-dev babel-loader @babel/core @babel/preset-env
webpack
@babel/present-env
includes all the released features,
and transpiles to suport all active browsers.
Optionally configure target browsers using browserlist queries.
See also https://browserl.ist/
To use stage-# features, include plugins for each feature.
stage-# presets are deprecated.
Source: tc39.github.io/process-document/
Yes.
Use WebPack and Babel
to transpile an ES6/7/8 app into an ES5 file.
Sprinkle in sparingly.
Don't use it just to use it.
Use it when it adds clarity
and simplicity to your code.
Code like the person maintaining your code is a homicidal maniac that knows where you live.
Variable scopingES5: var
function hello() {
console.log(message);
// undefined
if (true) {
var message = 'hello world';
console.log(message);
// 'hello world'
}
console.log(message);
// 'hello world'
}
ES6: let, const
function hello() {
console.log(message);
// exception
if (true) {
let message = 'hello world';
console.log(message);
// 'hello world'
}
console.log(message);
// exception
}
Variable scoping
"fat arrow" functionsES5: function
var array = [1,2,3];
array.map(function (a) {
return a * 2;
});
ES6: =>
var array = [1,2,3];
array.map(a => a * 2);
"fat arrow" functionsthis when defined
"fat arrow" functionsBuild it up
function (a) { return a * 2; }
(a) => { return a * 2; }
a => { return a * 2; }
a => a * 2
(a) => a * 2
All of these are valid ES6 syntax
"fat arrow" functionsReturning JS Object
function (a) { return {name: a}; }
(a) => { return {name: a}; }
a => {name: a} // <-- BROKEN
a => ({name: a})
ClassesES5: constructor function
function Person(name) {
this.name = name;
}
Person.prototype.speak = function () {
console.log('hello '+this.name);
};
ES6: class
class Person {
constructor(name) {
this.name = name;
}
speak() {
console.log('hello '+this.name);
}
}
ClassesAsynchronous resolve
ES5: callback
function doWork(cb) {
cb(null, 'results');
}
doWork(function (err, results) {
if (err) {
// handle error
}
// handle success
});
ES6: promise
function doWork() {
return new Promise(function (success, fail) {
success('result');
});
}
doWork().then(function (result) {
// handle success
}).catch(err) {
// handle error
});
Asynchronous resolve
Modulesimport and export
ModulesES5:
ES6: export and import
// -------- lib.js --------
export function square(x) {
return x * x;
}
// -------- main.js --------
import * as lib from './lib';
lib.square(4); // 16
ModulesNode:
// -------- lib.js --------
function square(x) {
return x * x;
};
module.exports = {
square: square
};
// -------- main.js --------
var lib = require('./lib');
lib.square(4); // 16
ES6: export and import
// -------- lib.js --------
export function square(x) {
return x * x;
}
// -------- main.js --------
import * as lib from './lib';
lib.square(4); // 16
ModulesNode:
// -------- lib.js --------
function square(x) {
return x * x;
}
module.exports = {
default: square
};
// -------- main.js --------
var lib = require('./lib').default;
lib(4); // 16
ES6: export and import
// -------- lib.js --------
export default function (x) {
return x * x;
}
// -------- main.js --------
import lib from './lib';
lib(4); // 16
String TemplatesES5: add strings
var a = 5;
var b = 10;
var msg = "Fifteen is " + (a + b) + " and\n";
message += "not " + (2 * a + b) + ".");
console.log(msg);
// "Fifteen is 15 and
// not 20."
ES6: string templates
var a = 5;
var b = 10;
var msg = `Fifteen is ${a + b} and
not ${2 * a + b}.`;
console.log(msg);
// "Fifteen is 15 and
// not 20."
String Templates
Building objects
Building objectsES5:
var x = 3;
var y = 7;
var c = {
x: x,
y: y
};
ES6:
var x = 3;
var y = 7;
var c = { x, y };
Building objectsES5:
var x = 3;
var y = 7;
var c = {
x: x,
y: y,
z: 9
};
ES6:
var x = 3;
var y = 7;
var c = {
x,
y,
z: 9
};
Dereferencing objectsES5:
var c = { x: 3, y: 7 };
var x = c.x;
var y = c.y;
console.log(x); // 3
ES6:
var c = { x: 3, y: 7 };
let { x, y } = c;
console.log(x); // 3
Dereferencing objectsES5:
ES6:
// -------- lib.js --------
export function square(x) {
return x * x;
}
export function double(x) {
return x * 2;
}
// -------- main.js --------
import { square, double } from './lib';
square(4); // 16
double(4); // 8
Rest parametersES5:
function (a, b) {
var theRest = Array.prototype.slice.call(arguments);
theRest.shift(); // a
theRest.shift(); // b
theRest.forEach(function (g) {
// ...
});
}
ES6:
function(a, b, ...theRest) {
theRest.forEach(function (g) {
// ...
});
}
Rest parameters
Spread operatorPass an array like a series of arguments
ES5:
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction.apply(null, args);
ES6:
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);
Spread operator
Spread operatorA more powerful array literal
ES5:
var parts = ['shoulders', 'knees'];
// duplicate array
var lyrics = parts.slice();
lyrics.unshift('head');
lyrics.push('and');
lyrics.push('toes');
// ["head", "shoulders", "knees",
// "and", "toes"]
ES6:
var parts = ['shoulders', 'knees'];
var lyrics = [
'head',
...parts,
'and',
'toes'
];
// ["head", "shoulders", "knees",
// "and", "toes"]
Rest and Spread operatorsA more powerful array literal
Rest:
function (a, b, ...theRest) {
theRest.forEach(function (g) {
// ...
});
}
Spread:
var args = [0, 1, 2];
myFunction(...args);
async / awaitES6: promises
function doWork() {
return new Promise(function (success, fail) {
success('result');
});
}
doWork().then(function (result) {
// handle success
}).catch(err) {
// handle error
});
ES8: async / await
async function doWork() {
// something asynchronous
return 'result';
}
try {
let result = await doWork();
} catch (err) {
// handle error
}
async / await
async / await
Source: bram.us/2017/05/09/javascript-from-callbacks-to-promises-to-asyncawait-in-7-seconds/
Remember: sugar over existing features
Sprinkle in sparingly to add legibility
Don't add new features to show off
| ES6,7,8+ -> ES5 | babeljs.io |
| import and export | webpack.github.io |
| Anything else | Polyfill as needed |
| React (create-react-app) |
Webpack & Babel with JSX plugin |
| Angular CLI | Webpack & TypeScript |
| Vue.js CLI | Webpack & Babel or TypeScript |
| Aurelia CLI | Webpack & Babel or TypeScript |
You can use modern JavaScript today.