ECMAScript 2015 Tips & Traps

37

Transcript of ECMAScript 2015 Tips & Traps

Page 1: ECMAScript 2015 Tips & Traps
Page 2: ECMAScript 2015 Tips & Traps

ECMAScript 2015Tips & Traps

Adrian-Tudor Panescu

Iasi, November 2015

Page 3: ECMAScript 2015 Tips & Traps

Presentation online

https://j.mp/ecmas2015

Page 4: ECMAScript 2015 Tips & Traps

About me

adrian.panescu.com@adrop

4

Page 5: ECMAScript 2015 Tips & Traps

5

Page 6: ECMAScript 2015 Tips & Traps

What’s all about?

● 500+ new features● Backwards-compatible● A much-awaited update (~6 years)● Hopefully the step to a yearly release cycle

6

Page 7: ECMAScript 2015 Tips & Traps

ES6 or ES2015?

https://twitter.com/JavaScriptDaily/status/662020174837583872

7

Page 8: ECMAScript 2015 Tips & Traps

Where are we?

Source: https://kangax.github.io/compat-table/es6/05.11.2015

8

Page 9: ECMAScript 2015 Tips & Traps

Where are we?

https://babeljs.io/ 9

Page 10: ECMAScript 2015 Tips & Traps

Where are we?

https://twitter.com/JavaScriptDaily/status/660074434821246976

10

Page 11: ECMAScript 2015 Tips & Traps

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

Page 12: ECMAScript 2015 Tips & Traps

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

Page 13: ECMAScript 2015 Tips & Traps

Trap: arrow functions and arguments

function foo() {

console.log(arguments);

}

foo(1); // [1]

var foo = () => {

console.log(arguments);

}

foo(1); // ReferenceError

13

Page 14: ECMAScript 2015 Tips & Traps

Trap: arrow functions and arguments

● Use rest parameters: (...args) => args● Babel uses arguments from enclosing scope (?)

14

Page 15: ECMAScript 2015 Tips & Traps

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

Page 16: ECMAScript 2015 Tips & Traps

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!’);

}

}

Page 17: ECMAScript 2015 Tips & Traps

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

Page 18: ECMAScript 2015 Tips & Traps

Trap: Temporal Dead Zone (TDZ)

{

console.log(x); // undefined

var x = ‘codecamp’;

}

{

console.log(x); // ReferenceError

let x = ‘codecamp’;

}

18

Page 19: ECMAScript 2015 Tips & Traps

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

Page 20: ECMAScript 2015 Tips & Traps

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/

Page 21: ECMAScript 2015 Tips & Traps

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

Page 22: ECMAScript 2015 Tips & Traps

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]);

}

22http://stackoverflow.com/questions/31987465/ecmascript-2015-const-in-for-loops

Page 23: ECMAScript 2015 Tips & Traps

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);

}

23http://stackoverflow.com/questions/31987465/ecmascript-2015-const-in-for-loops

Page 24: ECMAScript 2015 Tips & Traps

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

Page 25: ECMAScript 2015 Tips & Traps

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

Page 26: ECMAScript 2015 Tips & Traps

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

Page 27: ECMAScript 2015 Tips & Traps

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

Page 28: ECMAScript 2015 Tips & Traps

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

Page 29: ECMAScript 2015 Tips & Traps

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

Page 30: ECMAScript 2015 Tips & Traps

Tip: Promise-driven architecture

function foo() {

return 42;

}

function foo() {

return Promise.resolve(42);

}

30

Page 31: ECMAScript 2015 Tips & Traps

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

Page 32: ECMAScript 2015 Tips & Traps

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

Page 33: ECMAScript 2015 Tips & Traps

Tip: simple things

delete foo[‘bar’]

parseInt(‘1337’, 10)

Reflect.deleteProperty(foo, ‘bar’)

Number.parseInt(‘1337’, 10)

33

Page 34: ECMAScript 2015 Tips & Traps

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

Page 36: ECMAScript 2015 Tips & Traps