Yifei Kong

May 30, 2017

EcmaScript 6

using es6 with babel

debugging mode

<script src="node_modules/babel-core/browser.js"></script> 
<script type="text/babel"> 
// Your ES6 code
</script>

production mode

babel script.js --out-file script-compiled.js

Yifei's Notes

the main impovements of ES6 are loops and generators, let/const, arrow functions, class syntax small pieces are function arguments, destructuring

Looping

there are 3 ways to loop a sequence in ES5, but there are problems

ES5 Loops

// not concise for (var index = 0; index < myArray.length; index++) { console.log(myArray[index]); }

// no break or return myArray.forEach(function (value) { console.log(value); });

// for objects, not arrays for (var index in myArray) { // don't actually do this console.log(myArray[index]); }

Introducing ES6 Loops

// concise and correct for (let value of myArray) { console.log(value); }

// also works on strings, sets and maps for (let chr of "") { alert(chr); }

// make a set from an array of words var uniqueWords = new Set(words); for (let word of uniqueWords) { console.log(word); }

for (var [key, value] of phoneBookMap) { console.log(key + "'s phone number is: " + value); }

// you can even make it work with objects // dump an object's own enumerable properties to the console for (var key of Object.keys(someObject)) { console.log(key + ": " + someObject[key]); }

Generator

Inside a generator-function, yield is a keyword, with syntax rather like return. The difference is that while a function (even a generator-function) can only return once, a generator-function can yield any number of times. The yield expression suspends execution of the generator so it can be resumed again later.

Generator functions are basically the pause-and-continue-able function. when you call a generator function, it returns an paused Generator object, which has a next() function, each time you call the next() function, a pair of yielded-value and status is returned.

In technical terms, each time a generator yields, its stack frame—the local variables, arguments, temporary values, and the current position of execution within the generator body—is removed from the stack. However, the Generator object keeps a reference to (or copy of) this stack frame, so that a later .next() call can reactivate it and continue execution.

function* fibs() { var a = 0; var b = 1; while (true) { yield a; [a, b] = [b, a + b]; } }

function* range(start, stop) { for (var i = start; i < stop; i++) yield i; }

// This should "ding" three times for (var value of range(0, 3)) { alert("Ding! at floor #" + value); }

This is possible because generators are iterators. All generators have a built-in implementation of .next() and Symbol.iterator.

Template Strings

Hello ${user.name}, welcome to our server for the ${times} times

Rest Parameters and Defaults

ES5 version

function containsAll(haystack) {
  for (var i = 1; i < arguments.length; i++) {
    var needle = arguments[i];
    if (haystack.indexOf(needle) === -1) {
      return false;
  }
}
return true;
}

ES6 version

function containsAll(haystack, ...needles) {
  for (var needle of needles) {
    if (haystack.indexOf(needle) === -1) {
      return false;
  }
}
return true;
}

ES6 supports default parameters, The default argument gets evaluated at call time, so unlike e.g. in Python, a new object is created each time the function is called.

Class

ES6 support static method, supuer, getter/setter you can even subclass builtin types

class Circle { constructor(radius) { this.radius = radius; Circle.circlesMade++; };

static draw(circle, canvas) {
    // Canvas drawing code
};

static get circlesMade() {
    return !this._count ? 0 : this._count;
};
static set circlesMade(val) {
    this._count = val;
};

area() {
    return Math.pow(this.radius, 2) * Math.PI;
};

get radius() {
    return this._radius;
};
set radius(radius) {
    if (!Number.isInteger(radius))
        throw new Error("Circle radius must be an integer.");
    this._radius = radius;
};

}

var [,,third] = ["foo", "bar", "baz"]; var [head, ...tail] = [1, 2, 3, 4]; console.log(tail); // [2, 3, 4]

var robotA = { name: "Bender" }; var robotB = { name: "Flexo" };

var { name: nameA } = robotA; var { name: nameB } = robotB;

console.log(nameA); // "Bender" console.log(nameB); // "Flexo"

// this is a syntax sugar for variable and key share the same name var { foo, bar } = { foo: "lorem", bar: "ipsum" }; console.log(foo); // "lorem" console.log(bar); // "ipsum"

var [missing = true] = []; console.log(missing); // true

var { message: msg = "Something went wrong" } = {}; console.log(msg); // "Something went wrong"

var { x = 3 } = {}; console.log(x); // 3

// parameters function removeBreakpoint({ url, line, column }) { // ... }

// super works as expected, calling super constructor and access base properties

// you can even subclass builtin types

CommonJS

There is a special object called module.exports, when requireing, the value of module.exports is returned.

something like that... var require = function(path) { // ... return module.exports; };

ES6 export

use the export keyword

// lib.js export function foo() {} export class bar {} // or export {baz, foz}; export {foo as fart};

// use.js import {foo, bar} from "lib.js"; import {foo as fart} from "lib.js"; // renaming import {* as lib} from "lib.js"; // import everything and put in a object

ES6 import commonJS

most packages are written in commonJS, for using as ES6 modules: import _ from "lodash" // which is import {default as _} from "lodash" // which is let _ = require("lodash");

you can also do module.exports in ES6 export default value;