ECMAScript 6 v2

meta-meta-programming?

© 2016 Last Minute Panic Productions

Tech Lead at Norse Corp

Angularhead, stream processing hacker

We do this!

What's with all the numbers?

ES through the ages

Version Year
1 1997
2 1998
3 1999
5 2009
5.1 2011
6 2015

Sugary Treats!

(and you didn't even need to wear a costume)

Arrows:

// ES5
Randall.on('stress', function () { 
    // handle stress (badly);
});
['Odin', 'Thor', 'Bob'].map(function () {
    // ...
});
fetch('https://rkoutnik.com')
.then(function (data) {
    // Brilliant programming articles!
})
.catch(function (error) {
    // Works on my machine
});
// ES6
Randall.on('stress', () => {
// handle stress (badly);
});
['Odin', 'Thor', 'Bob'].map(() => {
// ...
});
fetch('https://rkoutnik.com')
.then((data) => {
// Brilliant programming articles!
})
.catch((error) => {
// Works on my machine
});
No more
funciton
funtion
functoin
┻━┻ ヘ╰( •̀ε•́ ╰)

What's this?

var that = this;
var _this = this;
var that_or_this = this;
this.on('stress', function () {
  that.handleStress();
});
this.on('stress', () => {
  this.handleStress();
});

More neat arrow tricks

// You can omit the parens when you have a single arg
['bill', 'bob', 'jeb', 'valentina'].map(kerb => {
  return kerb.intoSpace();
});
// Heck, with a single instruction, you can drop the brackets
['bill', 'bob', 'jeb', 'valentina'].map(kerb => kerb.intoSpace());
// Noop
() => {}
// Constant function
() => 42

Template strings

let str = 'Hello, ' + person.name + '!';
let str = `Hello, ${person.name}!`;
let str = `----- PERSON -----
name: ${person.name}
hobby: ${person.hobby}
salary: $${person.salary.toLocaleString()}`;

Tagged template strings

console.log(`
 ----- ${name.toUpperCase()} RESULTS -----
 ${MESSAGES} messages sent in ${(time / 1000).toLocaleString()} seconds
 ${(MESSAGES / (time / 1000)).toLocaleString()} messages/sec
`);
let myTag = (strings, ...values) => {
return strings.reduce((prev, next, idx) => {
let val = values[idx];
if (val && Number(val) === val) {
val = val.toLocaleString();
}
return prev + next + val;
}, '');
}
console.log(myTag`
----- ${name.toUpperCase()} RESULTS -----
${MESSAGES} messages sent in ${time / 1000} seconds
${MESSAGES / (time / 1000)} messages/sec
`);

Classes

We're all grown up like Java

function Cat (name) {
  this.name = name;
}
Cat.prototype.introduce = function () {
  return 'Hi everyone! I\'m'
      + this.name;
};
function Fuzz () {
  Cat.call(this, 'Fuzz');
}
Fuzz.prototype = Object.create(Cat.prototype);
Fuzz.prototype.sayHi = function sayHi() {
  return Cat.prototype.sayHi.call(this)
      + ', and I'd like some food';
};
var fuzz = new Fuzz();
fuzz.sayHi();
class Cat {
constructor (name) {
this.name = name;
}
sayHi () {
return `Hi everyone. I'm ${this.name}`
}
}
class Fuzz extends Cat {
constructor () {
super('Fuzz');
}
sayHi () {
return `${super.sayHi()} and I'd like some food!`;
}
}
let fuzz = new Fuzz;
fuzz.sayHi();

Getters & Setters

(Even more Java-like)

function Cat (name) {
  this._name = name;
  Object.defineProperty(this, 'name', {
    get: function () {
      return this._name;
    },
    set: function (newName) {
      this._name = newName;
    }
  });
}
class Cat {
constructor (name) {
this._name = name;
}
get name () {
return this._name;
}
set name (newName) {
this._name = newName;
}
}

Object destructuring

var id = getNextId();
var employee = getEmployeeById(id);
var employeeOptions = {
  id: id
};
employeeOptions[employee.name] = employee;
var id = getNextId();
var employee = getEmployeeById(id);
var employeeOptions = {
id,
[employee.name]: employee
};

Multiple return!

(I can haz Python)

var getThings = () => {
// Some data munging
return [thing1, thing2];
};
var [myThing1, myThing2] = getThings();
console.log(myThing1);

let & const

...back to Java

function example() {
  if (exampleIsFunny) {
    var meta = true;
  }
  console.log(meta); // true
}
function example() {
if (exampleIsFunny) {
let meta = true;
}
console.log(meta); // error
}
for(var i = 0; i < 10; i++) {
  setTimeout(() => console.log(i), 10);
}
9, 9, 9, 9, 9, 9, 9, 9, 9, 9
for(let i = 0; i < 10; i++) {
setTimeout(() => console.log(i), 10);
}
0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Temporal dead zone

(function () {
'use strict';
console.log(bill); // undefined
var bill = 'llama';
})();
(function () {
'use strict';
console.log(bill); // error
let bill = 'llama';
})();
const name = 'Randall';
name = 'hackerman';  // throws
const person = {
  name: 'Randall'
};
person.name = 'hackerman';  // throws?
if (youShouldNotDoThis) {
  function agh() {}
}
agh(); // throws

Fun with Functions

JavaScript goes "splat"

Default arguments

function build (what) {
  what = what || 'presentation';
  return what; // Say 'what' again
}
build(); // 'presentation'
function build (what = 'presentation') {
return what;
}
build(); // 'presentation'

Spread operator

let f = () => {
console.log(arguments); // error!
});
f(1,2,3);
let f = (...args) => {
console.log(args); // [1,2,3]
});
f(1,2,3);

Spread pt 2

let f = (firstName, lastName) => {
  console.log(firstName, lastName); // 'Randall', 'Koutnik'
});
let nameArr = ['Randall', 'Koutnik'];
f(...nameArr);

TRANSPILING

Babel

A tower of code!

How?

TypeScript

Because JS needs types!

let register = (type: string, name: string, factory): INodeFactory => {
export interface INodeFactory {
(...config: any[]): symbol;
}

TypeScript in action

INTERLUDE

npm scripts

Wow, that was a lot

Any questions before we move on?

Proxies

No, not the kind that get you past the firewall

World's simplest proxy

let target = {};
let handler = {};
let prox = new Proxy(target, handler);
prox.world = 'hello';
console.log(target.world); // Hello
let handler = {
  get (target, key) {
    return target[key] + '!';
  }
}
let target = {};
let proxy = new Proxy(target, handler);
proxy.world = 'hello';
console.log(proxy.world); // 'hello!'
let handler = {
  get (target, key) {
    return target[key] + '!';
  }
  set (target, key, value) {
    if (typeof key !== 'string') {
      throw new Error(`Tried to set ${key} to non-string value ${value}`);
    }
    target[key] = value;
    return true;
  }
}
let target = {};
let proxy = new Proxy(target, handler);
proxy.world = 'hello';
console.log(proxy.world); // 'hello!'
proxy.bad = {}; // Throws!
let ng = (function () {
  let handler = {
    get (target, key) {
      if (key.indexOf('$$') === 0) {
        throw new Error(`Don't go touching the internals!`);
      }
      return target[key];
    }
    set (target, key, value) {
      if (key.indexOf('$') === 0) {
        throw new Error(`Don't go touching the internals!`);
      }
      target[key] = value;
      return true;
    }
  }
  let target = angular;
  return new Proxy(target, handler);
})();

Me

questions@rkoutnik.com

github.com/SomeKittens

Awesome folks & more reading