ES6 (Week I)

@ Rakuten Taiwan weekly meetup

ES6

a.k.a

ES2015

Agenda

  • let/const
  • Template literals
  • Default function parameters
  • Rest parameter
  • Spread operator
  • Method definition
  • Property shorthands
  • Computed property keys
  • Arrow function
  • for-of
  • Class

let

  • Block Scope
    • Block scoping means it can shadow variables within a function
  • Mutable
function order(x, y) {
    if (x > y) {
        let tmp = x;
        x = y;
        y = tmp;
    }
    console.log(tmp === x); // ReferenceError: tmp is not defined
    return [x, y];
}

const

  • Block Scope
    • Block scoping means it can shadow variables within a function
  • Immutable (?)
    • const is not really immutable; it's just never re-assigned.
    • If re-assigning value to a const, it will throw TypeError.
const foo;
    // SyntaxError: missing = in const declaration

const bar = 123;
bar = 456;
    // TypeError: `bar` is read-only

Temporal Dead Zone 

In ECMAScript 6, accessing a let or const variable before its declaration (within its scope) causes a ReferenceError. The time span when that happens, between the creation of a variable’s binding and its declaration, is called the temporal dead zone.

- Dr. Axel Rauschmayer

TDZ (Cont.) 

  • typeof throws a ReferenceError for a variable in the TDZ
// Example from exploringjs

typeof tmp === 'boolean'; // ReferenceError
let tmp = true;
if (true) { // enter new scope, TDZ starts
    // Uninitialized binding for `tmp` is created
    console.log(tmp); // ReferenceError

    let tmp; // TDZ ends, `tmp` is initialized with `undefined`
    console.log(tmp); // undefined

    tmp = 123;
    console.log(tmp); // 123
}
console.log(tmp); // true

String Template

There are two kinds of literals:

  • Template literals: multi-line string literals that support interpolation
  • Tagged template literals: function calls

String Template (Cont.)

  • Use ${ and } to do string interpolation
  • Line terminators in template literals are always LF (\n)
  • backslash (\) is used for escaping inside template literals
  • multi-line on the fly
  • String.raw is a tagged string template function for raw strings. backslashes will have no special meaning.
// String interpolation
const name = 'Haku';
console.log(`Hello, ${name}
Welcome to Rakuten!`);
console.log(`Use backslash(\\) as same as
normal string to escape itself.`)

// Output:
// Hello, Haku
// Welcome to Rakuten!
// Use backslash(\) as same as
// normal string to escape itself.

String.raw`You can use
\nthis multiple lines
\rexample string
\tto check
how String.raw works
\n`;

Tagged Template Literal

String Template (Cont.)

sayHello`Hello, ${name}
Welcome to ${companyName}!`

// equal to below syntax

sayHello(
  ['Hello, ', '\nWelcome to ', '!'],
  name,
  companyName
)

Putting a template string after function expression without parentheses will trigger a function call.

Check following example: 

Tagged Template Literal (Cont.)

String Template (Cont.)

The tag function will receive Template strings as first parameter and Substitutions (such as name in the previous example) as other parameters.

Besides, tag function will receive two versions of template strings:

1. raw: backslashes are not interpreted

2. cooked: backslashes are special

Check next page for full sample code.

Tagged Template Literal (Cont.)

String Template (Cont.)

function sayHello(literals, ...subs) {
  return literals.reduce((result, lit, idx) => (
    (idx < subs.length) ?
      `${result}${lit}${subs[idx].toUpperCase()}` :
      `${result}${lit}`
  ), '');
}

const name = 'Haku';
const companyName = 'Rakuten';
sayHello`Hello, ${name}
Welcome to ${companyName}!`

// Output:
// Hello, HAKU
// Welcome to RAKUTEN!

Default function parameters

Initialize parameter values with default value if no value or undefined is passed, default to undefined.

function add(a, b = 1) {
  return a + b;
}

add(1, 2); // 3
add(1, 1); // 2
add(1);    // 2
add(1, undefined); // 2

Rest Parameters

Use rest parameters (...) as the last parameter in function, then it will receive all remaining  actual parameters in an Array. If there's no remaining parameters, it will be empty array.

function doSomething(x, ...y) {
  // do something
}

doSomething(1, 2, 3);
// x = 1, y = [2, 3]

doSomething(1);
// x = 1, y = []

Spread Operator

It looks like rest operator, but is its opposite.

ES5 ES6
[1, 2].concat(more) [1, 2, ...more]
list.push.apply(list, [3, 4]) list.push(...[3, 4])
a = list[0], rest = list.slice(1) [a, ...rest] = list
console.log(1, 2, 3) console.log(...[1, 2, 3])
Array.prototype.slice.apply(document.querySelectorAll('div')) [...document.querySelectorAll('div')]

Method Definition

It is a shorthand for a function assigned to the method's name.

var obj = {
  foo() {
    /* code */
  },
  bar() {
    /* code */
  }
};

var obj2 = { 
  * g() {
    var index = 0;
    while(true)
      yield index++;
  }
};
var obj = {
  foo: function() {
    /* code */
  },
  bar: function() {
    /* code */
  }
};

var obj2 = {
  g: function*() {
    var index = 0;
    while(true)
      yield index++;
  }
};

ES6

ES5

Property Shorthands

When the property key is as same as the name of the variable that specifies the property value, then you can use property shorhands.

const x = 4;
const y = 1;

const obj = { x, y };
// is equivalent to
const obj = { x: x, y: y };

// it can work well with `destructuring`
const obj = { x: 4, y: 1 };
const { x, y } = obj;
console.log(x); // 4
console.log(y); // 1

Computed property keys

It allows you to write an expression wrapped in squared brackets instead of regular property name

const name = 'name'
const user = { [name]: 'Haku' }
console.log(user)
// { name: 'Haku' }

function getType(type) {
  return {
    [type]: {
      message: `${type} type`,
      date: new Date()
    },
  };
}
var name = 'name'
var user = {}
user[name] = 'Haku'
console.log(user)
// { name: 'Haku' }

function getType(type) {
  var obj = {};
  obj[type] = {
    message: type + ' type',
    date: new Date()
  };
  return obj;
}

ES6

ES5

// Example from MDN

function Person() {
  var that = this;
  that.age = 0;

  setInterval(function growUp() {
    // The callback refers to the
    // `that` variable of which
    // the value is
    // the expected object.
    that.age++;
  }, 1000);
}

var person = new Person();

Arrow Function

Example

// Example from MDN

function Person(){
  this.age = 0;

  setInterval(() => {
    // |this| properly refers to
    // the person object
    this.age++;
  }, 1000);
}

var p = new Person();

Compare with traditional function expression

var bob = {
  _name: 'Bob',
  _friends: ['Haku'],
  printFriends() {
    this._friends.forEach(f =>
      console.log(
        `${this._name} knows ${f}`
      )
    );
  }
};

bob.printFriends();
// Output: Bob knows Haku

Arrow Function (Cont.)

Example

var bob = {
  _name: 'Bob',
  _friends: [],
  printFriends: function () {
    this._friends.forEach(function (f) {
      console.log(
        this._name + ' knows ' + f
      );
    }, this);
  }
};

bob.printFriends();
// Output: Bob knows Haku

ES6

ES5

Arrow Function (Cont.)

Syntax

// Normal syntax
var add = (a, b) => {
  return a + b;
};

// Without curly braces,
// the expression body
// will be returned.
var add = (a, b) => a + b;

// Normal syntax
// on single parameter
var toUpper =
  (string) => string.toUpperCase();

// Single parameter
// without parentheses
var toUpper =
  string => string.toUpperCase();
// Function without parameters
// must have parentheses
var sayHi =
  () => console.log('Hi');

// returning an object
// must use parentheses.
var getObj =
  () => ({})

console.log(typeof () => {});
// SyntaxError
console.log(typeof (() => {}));
// Output: "function"

const Car = () => {};
new Car();
// TypeError:
// Car is not a constructor

Arrow Function (Cont.)

Lexical variables

The source of this is an important distinguishing aspect of arrow functions:

  • Traditional functions have a dynamic this; its value is determined by how they are called.
  • Arrow functions have a lexical this; its value is determined by the surrounding scope.

Arrow Function

  • Arrow function expression is a shorter expression for function expression.
  • It will not bind its own this, arguments, super, or new.target.
  • Arrow functions are always anonymous functions
  • It cannot be constructor.
  • The variables mentioned above which won't bind their own this will bind to lexical.
  • Less verbose than traditional function expressions.

for-of

Loop over iterable objects (Arrays, strings, Maps, Sets, etc.)

const arr = ['a', 'b'];
for (const [index, element] of arr.entries()) {
    console.log(`${index}. ${element}`);
}

// Output:
// 0. a
// 1. b
const map = new Map([
    [false, 'no'],
    [true, 'yes'],
]);

for (const [key, value] of map) {
    console.log(`${key} => ${value}`);
}

// Output:
// false => no
// true => yes

Class

ES6 (Week 1)

By CYB

ES6 (Week 1)

ES6 (Week 1) @ Rakuten Taiwan weekly meetup

  • 1,136