ECMAScript 2015
Tips & Traps
Adrian-Tudor Panescu
Iasi, November 2015
Presentation online
https://j.mp/ecmas2015
About me
adrian.panescu.com
@adrop
4
5
What’s all about?
● 500+ new features
● Backwards-compatible
● A much-awaited update (~6 years)
● Hopefully the step to a yearly release cycle
6
ES6 or ES2015?
https://twitter.com/JavaScriptDaily/status/662020174837583872
7
Where are we?
Source: https://kangax.github.io/compat-table/es6/
05.11.2015
8
Where are we?
https://babeljs.io/
9
Where are we?
https://twitter.com/JavaScriptDaily/status/660074434821246976
10
Where am I?
● Using ES2015 in production for ~year
● 2nd
presentation on ES2015 at CodeCamp
● Reported Babel and ESLint bugs:
○ https://github.com/babel/babel/issues/2743
○ https://github.com/eslint/eslint/issues/3364
○ https://github.com/eslint/eslint/issues/3510
11
Tip: arrow functions and this
function Ping() {
this.count = 1;
setInterval(function() {
this.count += 1;
}.bind(this), 16.6);
}
function Ping() {
this.count = 1;
setInterval(() => {
this.count += 1;
}, 16.6);
}
12
Trap: arrow functions and arguments
function foo() {
console.log(arguments);
}
foo(1); // [1]
var foo = () => {
console.log(arguments);
}
foo(1); // ReferenceError
13
Trap: arrow functions and arguments
● Use rest parameters: (...args) => args
● Babel uses arguments from enclosing scope (?)
14
Tip: Classes
class Foo {
constructor(bar) {
this.bar = bar;
}
baz() {
return 42;
}
}
var Foo = function(bar) {
this.bar = bar;
}
Foo.prototype.baz = function() {
return 42;
}
15
Trap: forgetting about super()
class Foo {
constructor(baz) {
this.baz = baz;
}
}
class Baz extends Foo {
constructor(baz) {
super(baz);
console.log(this.baz);
}
} 16
class Foo {
shout() {
console.log(‘foo!’);
}
}
class Baz extends Foo {
shout() {
super.shout();
console.log(‘baz!’);
}
}
Tip: block scoping
function foo() {
for (var i = 0; i < 2; i++) {
var a = i;
}
console.log(a); // 1
}
function foo() {
for (var i = 0; i < 2; i++) {
let a = i;
}
console.log(a); // ReferenceError
}
17
Trap: Temporal Dead Zone (TDZ)
{
console.log(x); // undefined
var x = ‘codecamp’;
}
{
console.log(x); // ReferenceError
let x = ‘codecamp’;
}
18
Trap: Temporal Dead Zone (TDZ)
Section 13.3.1 in standard (sorry!):
let and const declarations define variables that are
scoped to the running execution context’s
LexicalEnvironment. The variables are created when
their containing Lexical Environment is instantiated but
may not be accessed in any way until the variable’s
LexicalBinding is evaluated. [...]
19
Trap: Temporal Dead Zone (TDZ)
var _temporalUndefined = {};
var x = _temporalUndefined;
function _temporalAssertDefined(val, name, undef) {
if (val === undef) {
throw new ReferenceError(name + " is not defined - temporal dead zone");
}
return true;
}
console.log(_temporalAssertDefined(x, "x", _temporalUndefined) && x);
x = ‘codecamp’;
20Your performance-related concerns: http://kpdecker.github.io/six-speed/
Tip: Iterators/ Generators and for...of
var a = [1, 3, 3, 7];
for (var e of a) {
console.log(e);
}
var a = [1, 3, 3, 7];
var l = a.length;
for (var i = 0; i < l; i++) {
console.log(a[i]);
}
21
Trap: Iterators and constants
var a = [1, 3, 3, 7];
for (const e of a) {
console.log(e);
}
var a = [1, 3, 3, 7];
var l = a.length;
for (const i = 0; i < l; i++) {
console.log(a[i]);
}
22
http://stackoverflow.com/questions/31987465/ecmascript-2015-const-in-for-loops
Trap: Iterators and constants
for (const e of a) {
console.log(e);
}
const it = a[Symbol.iterator]();
let res;
while (res = it.next() && !res.done) {
const e = __res.value;
console.log(e);
}
23
http://stackoverflow.com/questions/31987465/ecmascript-2015-const-in-for-loops
Tip: Promises
xhr(‘https://foo.com/’
function(resp) {
readHTML(resp,
function(html) {},
function(err) {})
},
function(err) {}
);
xhr(‘https://foo.com/’)
.then(readHTML)
.then(function(html) {})
.catch(function(err) {});
24
Tip: Promises
function xhr(url) {
return new Promise(function(resolve, reject) {
try {
// do some async work then...
resolve(data);
} catch(e) {
// if something goes wrong...
reject(e);
}
});
}
25
Trap: forgetting to return
xhr(‘https://foo.com/’)
.then((data) => {
readHTML(data);
})
.then((html) => {
console.log(html); // nope
}
.catch(console.error.bind(console));
xhr(‘https://foo.com/’)
.then((data) => {
return readHTML(data);
})
.then((html) => {
console.log(html); // okay
}
.catch(console.error.bind(console));
26
Trap: passing a non-function to .then()
xhr(‘https://foo.com/’)
.then(readHTML())
.then((result) => {
// XHR response
});
xhr(‘https://foo.com/’)
.then(readHTML)
.then((result) => {
// HTML response
});
27
Trap: .then(resolve, reject)
xhr(‘https://foo.com’)
.then(() => {
throw new ReferenceError;
}
.catch((err) => {
// never gonna give you up
console.log(err);
});
xhr(‘https://foo.com’)
.then(() => {
throw new ReferenceError;
},
(err) => {
// oblivious
console.log(err);
});
28
Trap: Array.forEach vs. Promises
getURLs()
.then((urls) => {
return
urls.forEach(readHTML);
})
.then(() => {
console.log(‘all urls read?’);
})
.catch(console.error.bind(console));
getURLs()
.then((urls) => {
return
Promise.all(urls.map(readHTML);
})
.then(() => {
console.log(‘all urls read!’);
})
.catch(console.error.bind(console));
29
Tip: Promise-driven architecture
function foo() {
return 42;
}
function foo() {
return Promise.resolve(42);
}
30
Tip: Reflect.apply
a = [99, 111, 100, 101, 99, 97, 109, 112];
String.fromCharCode.apply(null, a);
String.fromCharCode.call(null, a[0], a[1]));
a = [99, 111, 100, 101, 99, 97, 109, 112];
Reflect.apply(String.fromCharCode, null, a);
31
Trap: Reflect.apply expects an array
let a = [‘hello’, ‘world’]
Reflect.apply(
e => console.log(e), null, a);
let a = [‘hello’, ‘world’]
Reflect.apply(
e => console.log(e), null, [a]);
Reflect.apply(console.log, console, a);
32
Tip: simple things
delete foo[‘bar’]
parseInt(‘1337’, 10)
Reflect.deleteProperty(foo, ‘bar’)
Number.parseInt(‘1337’, 10)
33
Fin
● ECMAScript 2015 brings many nice features
● Solves some of ES5’s strangeness
○ Hopefully we won’t have to revisit “The Good Parts”
● Browsers should really start catching up
○ Babel is here to stay
○ Transpilers will always have a performance handicap
● We had 5 ReferenceErrors
34
● http://jsrocks.org/2015/01/temporal-dead-
zone-tdz-demystified/
● https://stackoverflow.
com/questions/31987465/ecmascript-2015-const-
in-for-loops
● http://pouchdb.com/2015/05/18/we-have-a-
problem-with-promises.html
Resources
35
www.meetup.com/Iasi-JS/ www.meetup.com/Papers-We-Love-Iasi

ECMAScript 2015 Tips & Traps

  • 2.
    ECMAScript 2015 Tips &Traps Adrian-Tudor Panescu Iasi, November 2015
  • 3.
  • 4.
  • 5.
  • 6.
    What’s all about? ●500+ new features ● Backwards-compatible ● A much-awaited update (~6 years) ● Hopefully the step to a yearly release cycle 6
  • 7.
  • 8.
    Where are we? Source:https://kangax.github.io/compat-table/es6/ 05.11.2015 8
  • 9.
  • 10.
  • 11.
    Where am I? ●Using ES2015 in production for ~year ● 2nd presentation on ES2015 at CodeCamp ● Reported Babel and ESLint bugs: ○ https://github.com/babel/babel/issues/2743 ○ https://github.com/eslint/eslint/issues/3364 ○ https://github.com/eslint/eslint/issues/3510 11
  • 12.
    Tip: arrow functionsand this function Ping() { this.count = 1; setInterval(function() { this.count += 1; }.bind(this), 16.6); } function Ping() { this.count = 1; setInterval(() => { this.count += 1; }, 16.6); } 12
  • 13.
    Trap: arrow functionsand arguments function foo() { console.log(arguments); } foo(1); // [1] var foo = () => { console.log(arguments); } foo(1); // ReferenceError 13
  • 14.
    Trap: arrow functionsand arguments ● Use rest parameters: (...args) => args ● Babel uses arguments from enclosing scope (?) 14
  • 15.
    Tip: Classes class Foo{ constructor(bar) { this.bar = bar; } baz() { return 42; } } var Foo = function(bar) { this.bar = bar; } Foo.prototype.baz = function() { return 42; } 15
  • 16.
    Trap: forgetting aboutsuper() class Foo { constructor(baz) { this.baz = baz; } } class Baz extends Foo { constructor(baz) { super(baz); console.log(this.baz); } } 16 class Foo { shout() { console.log(‘foo!’); } } class Baz extends Foo { shout() { super.shout(); console.log(‘baz!’); } }
  • 17.
    Tip: block scoping functionfoo() { for (var i = 0; i < 2; i++) { var a = i; } console.log(a); // 1 } function foo() { for (var i = 0; i < 2; i++) { let a = i; } console.log(a); // ReferenceError } 17
  • 18.
    Trap: Temporal DeadZone (TDZ) { console.log(x); // undefined var x = ‘codecamp’; } { console.log(x); // ReferenceError let x = ‘codecamp’; } 18
  • 19.
    Trap: Temporal DeadZone (TDZ) Section 13.3.1 in standard (sorry!): let and const declarations define variables that are scoped to the running execution context’s LexicalEnvironment. The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated. [...] 19
  • 20.
    Trap: Temporal DeadZone (TDZ) var _temporalUndefined = {}; var x = _temporalUndefined; function _temporalAssertDefined(val, name, undef) { if (val === undef) { throw new ReferenceError(name + " is not defined - temporal dead zone"); } return true; } console.log(_temporalAssertDefined(x, "x", _temporalUndefined) && x); x = ‘codecamp’; 20Your performance-related concerns: http://kpdecker.github.io/six-speed/
  • 21.
    Tip: Iterators/ Generatorsand for...of var a = [1, 3, 3, 7]; for (var e of a) { console.log(e); } var a = [1, 3, 3, 7]; var l = a.length; for (var i = 0; i < l; i++) { console.log(a[i]); } 21
  • 22.
    Trap: Iterators andconstants var a = [1, 3, 3, 7]; for (const e of a) { console.log(e); } var a = [1, 3, 3, 7]; var l = a.length; for (const i = 0; i < l; i++) { console.log(a[i]); } 22 http://stackoverflow.com/questions/31987465/ecmascript-2015-const-in-for-loops
  • 23.
    Trap: Iterators andconstants for (const e of a) { console.log(e); } const it = a[Symbol.iterator](); let res; while (res = it.next() && !res.done) { const e = __res.value; console.log(e); } 23 http://stackoverflow.com/questions/31987465/ecmascript-2015-const-in-for-loops
  • 24.
    Tip: Promises xhr(‘https://foo.com/’ function(resp) { readHTML(resp, function(html){}, function(err) {}) }, function(err) {} ); xhr(‘https://foo.com/’) .then(readHTML) .then(function(html) {}) .catch(function(err) {}); 24
  • 25.
    Tip: Promises function xhr(url){ return new Promise(function(resolve, reject) { try { // do some async work then... resolve(data); } catch(e) { // if something goes wrong... reject(e); } }); } 25
  • 26.
    Trap: forgetting toreturn xhr(‘https://foo.com/’) .then((data) => { readHTML(data); }) .then((html) => { console.log(html); // nope } .catch(console.error.bind(console)); xhr(‘https://foo.com/’) .then((data) => { return readHTML(data); }) .then((html) => { console.log(html); // okay } .catch(console.error.bind(console)); 26
  • 27.
    Trap: passing anon-function to .then() xhr(‘https://foo.com/’) .then(readHTML()) .then((result) => { // XHR response }); xhr(‘https://foo.com/’) .then(readHTML) .then((result) => { // HTML response }); 27
  • 28.
    Trap: .then(resolve, reject) xhr(‘https://foo.com’) .then(()=> { throw new ReferenceError; } .catch((err) => { // never gonna give you up console.log(err); }); xhr(‘https://foo.com’) .then(() => { throw new ReferenceError; }, (err) => { // oblivious console.log(err); }); 28
  • 29.
    Trap: Array.forEach vs.Promises getURLs() .then((urls) => { return urls.forEach(readHTML); }) .then(() => { console.log(‘all urls read?’); }) .catch(console.error.bind(console)); getURLs() .then((urls) => { return Promise.all(urls.map(readHTML); }) .then(() => { console.log(‘all urls read!’); }) .catch(console.error.bind(console)); 29
  • 30.
    Tip: Promise-driven architecture functionfoo() { return 42; } function foo() { return Promise.resolve(42); } 30
  • 31.
    Tip: Reflect.apply a =[99, 111, 100, 101, 99, 97, 109, 112]; String.fromCharCode.apply(null, a); String.fromCharCode.call(null, a[0], a[1])); a = [99, 111, 100, 101, 99, 97, 109, 112]; Reflect.apply(String.fromCharCode, null, a); 31
  • 32.
    Trap: Reflect.apply expectsan array let a = [‘hello’, ‘world’] Reflect.apply( e => console.log(e), null, a); let a = [‘hello’, ‘world’] Reflect.apply( e => console.log(e), null, [a]); Reflect.apply(console.log, console, a); 32
  • 33.
    Tip: simple things deletefoo[‘bar’] parseInt(‘1337’, 10) Reflect.deleteProperty(foo, ‘bar’) Number.parseInt(‘1337’, 10) 33
  • 34.
    Fin ● ECMAScript 2015brings many nice features ● Solves some of ES5’s strangeness ○ Hopefully we won’t have to revisit “The Good Parts” ● Browsers should really start catching up ○ Babel is here to stay ○ Transpilers will always have a performance handicap ● We had 5 ReferenceErrors 34
  • 35.
  • 37.