WELCOME TO THE JUNGLE

Why Transpile?

Transpilation is complicated

Well, yes, but...

So is updating Javascript

Lots of moving parts

Disruptive to workflow

WTF

Turns out, languages are hard.

Regexes!

Try/catch!
switch!

ES3 brought...

Function binding!

Functional Array Methods
Defined Properties

ES5 brought...

ES6 will bring...

Fat Arrows!

Destructuring!

Rest Parameters!

Spread Operators!

Default Parameters!

Block-level bindings!

Template Strings!

Generators!

Classes!

Proxies!

Maps!  Sets!

Promises!

Symbols!

Function names!

New Static Methods!

Proper Tail Call Optimization!

ES6⇒ES2015
ES7ES2016
???⇒???

So Why Not ES6?

Cuz they said so

So What Can I Do?

(glad you asked)

Limitations

Some things we just can't make happen in ES5 alone

But we can get pretty close...

Block-level Bindings

Block-level Bindings

Block-level Bindings

is even scoped to plain blocks

let

Block-level Bindings

const foo = "I AM CONSTANT AS THE NORTHERN STAR";

foo = "NO UR NOT"; // Will not compile -- "foo" is read-only
const foo = {
  foo: 'bar'
};

foo.foo = 'baz';      // This is valid
foo = { foo: 'baz' }; // This is not

Consts are pretty nifty, too

Default Parameters

Shorthand defaults are simple, but dangerous!

Default parameters are good!

Rest & Spread

Rest & Spread

if (someBusinessLogic(data)) {
  return performSomeAction(data);
} else if (someOtherBusinessLogic(data, metadata)) {
  return performSomeAction(data, metadata);
}
let args;
if (someBusinessLogic(data)) {
  args = [data];
} else if (someOtherBusinessLogic(data, metadata)) {
  args = [data, metadata];
}
return performSomeAction(...args);

mise-en-place programming

Fat Arrows

Simplify one-line methods

Even use them with multi-line methods

Fat Arrows

.bind(this)
.bind(this)
.bind(this)

Fat Arrows

Now all sexy and clean-looking

Fat Arrows

{
  inheritedFunction: function() {
    someAsynchronousTask().then(function() {
      this.inherited(arguments);
    }.bind(this));
  }
}
{
  inheritedFunction: function() {
    var _args = arguments;
    someAsynchronousTask().then(function() {
      this.inherited(_args);
    }.bind(this));
  }
}
{
  inheritedFunction: function() {
    someAsynchronousTask().then(() => this.inherited(arguments));
  }
}

Destructuring

Just suck values right out of an array

You can even do it with objects

WHY NOT STRINGS?

Destructuring

Defaults

Parameters

Object Shorthand

Destructuring

Template Strings

Template Strings

Expressions can also be substituted

Template Strings

Tagged Template Literals are crazy, but very interesting

Template Strings

Maps & Sets

var obj = {};

obj.foo = 'foo';
obj.bar = 'bar';

'bar' in obj; // true

for (let k in obj) {
  console.log(obj[k], k);
}
// foo foo
// bar bar

delete obj.bar;
var map = new Map();

map.set('foo','foo');
map.set('bar','bar');

map.has('bar'); // true

map.forEach((value, key) =>
    console.log(key, value));
// foo foo
// bar bar

map.delete('bar');
map.clear();

map.set('foo', 'foo')
   .set('bar', 'bar')
   .set('baz', 'baz')
   .set('quux', 'quux');

let arbitrary_object = { lorem: 'ipsum' };
map.set(arbitrary_object, 'holy cow!');

map.size; // 5

Maps & Sets

var list = [];

list.push(1);
list.push(2);
list.push(3);
list.push(2);

list.length === 4;  // true

for (let value of list) {
  console.log(value);
}
// 1
// 2
// 3
// 2
var set = new Set();

set.add(1);
set.add(2);
set.add(3);
set.add(2);

set.size === 3; // true

set.forEach(value => console.log(value));
// 1
// 2
// 3

set.delete(1);
set.clear();

set.add(1)
   .add(2)
   .add(3);

let arbitrary_object = { lorem: 'ipsum' };
set.add(arbitrary_object);

set.has(1); // true

Maps & Sets

Maps and Sets are great

BUT

WHAT ABOUT MEMORY?

WeakMaps & WeakSets

let set = new WeakSet();

set.add(arbitrarily_large_object); // The object is loaded into WeakSet
                                   // just like Set, but now can still 
                                   // be garbage collected

set.add(3); // TypeError!  WeakMaps & WeakSets *MUST* use Objects.

set.size; // Nonexistent!

set.has(arbitrarily_large_object); // true
let map = new WeakMap();

map.set(arbitrarily_large_object, any_other_value);

map.set(3, any_other_value); // TypeError!

map.size; // Nonexistent!

map.has(arbitrarily_large_object); // true

Symbols

Symbols

Generators

function range(min, max, callback) {
    for (let i = min; i <= max; i++) {
      callback(i);
    }
}

range(2, 3, (i) => console.log(`calling for ${i}: `))
// calling for 2
// calling for 3
function* range(min, max) {
    for (let i = min; i <= max; i++) {
      yield i;
    }
}

for (let i of range(2, 3)) {
  console.log(`calling for ${i}`);
}
// calling for 2
// calling for 3

Generators

for-of

lets you iterate over values of an iterable

Generators

function* range(min, max) {
    for (let i = min; i <= max; i++) {
      yield i;
    }
}

let generator = range(2,3);
/**
 * generator ~= {
 *                 next: function() { [native code] },
 *                 throw: function() { [native code] },
 *                 return: function() { [native code] }
 *              }
 */

Generators

let result = generator.next();
/**
 * result = {
 *             value: 2,
 *             done: false
 *          }
 */
result = generator.next();
/**
 * result = {
 *             value: 3,
 *             done: false
 *          }
 */
result = generator.next();
/**
 * result = {
 *             done: true
 *          }
 */

Generators

           can also inject values into a function

yield

Generators

Generators

Generators

Generators

Generators

Generators

Want to iterate over your objects?

Generators

Spread works great with any Iterable

Promises

Promises

Promise.all

Promises

Promise.race

Async/Await

Classes

Classes

Proxies

let original = {};
let proxyDescriptor = {
  get: function(original, key, proxy) {
    console.log(`looking for ${key} in the original object`);
    if (key in original) {
      return original[key];
    } else {
      original[key] = {};
      return new Proxy(original[key], proxyDescriptor);
    }
  }
};
let proxy = new Proxy(original, proxyDescriptor);

proxy.foo.bar.this_name.is.arbitrary = 42;
console.log(proxy.foo.bar.this_name.is.arbitrary); // 42
console.log(original); // Object has been constructed to have nested objects

BabelJS REPL: https://goo.gl/Tv9Ebr

Native Modules

import Foo from "aFooModule";
import Bar from "aBarModule";
import * as ChangedName from "anotherModule";
import { map, zip } from "utils/lodash";

// ... do something with these dependencies

export default {
  myNewModule,
  otherItems
};
export class MyClass {
  // ...
}

export function relatedToMyClass() { ... }

let foo = 'bar';

export foo;

Function Binding

Function Binding

Object Spread Operator

Decorators

ES2015: WELCOME TO THE JUNGLE

By Mike McElroy

ES2015: WELCOME TO THE JUNGLE

  • 1,432