All notes
Es6

Intro

ES5, ES6, ES2015

byteArcher.com.

ES6 = ECMAscript2015 = ES2015.

ES5 is the plain old JS.

ECMAScript is a specification of a language. JavaScript is an implementation of that language among JScript and ActionScript.

Features

TBD: template strings, Promises.

arrow functions

developer.mozilla.org.

An arrow function expression has a shorter syntax than a function expression and does not have its own this, arguments, super, or new.target. These function expressions are best suited for non-method functions, and they cannot be used as constructors.

Two factors influenced the introduction of arrow functions: shorter functions and non-binding of this.



// ----- Basic Syntax

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// equivalent to: (param1, param2, …, paramN) => { return expression; }

// Parentheses are optional when there's only one parameter name:
(singleParam) => { statements }
singleParam => { statements }
singleParam => expression

// The parameter list for a function with no parameters should be written with a pair of parentheses.
() => { statements }

// ----- Advanced Syntax

// Parenthesize the body of function to return an object literal expression:
params => ({foo: bar})

// Rest parameters and default parameters are supported
(param1, param2, ...rest) => { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements }

// Destructuring within the parameter list is also supported
let f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c;
f();  
// 6

curried function

SO.



// First, examine this function with two parameters
let add = (x,y) => x + y;
add(2,3); //=> 5

// Here it is again in curried form …
let add = x => y => x + y;

add (2) // returns (y => 2 + y)
// In order to use our curried function, we have to call it a bit differently:
add(2)(3); // returns 5

var, let, const

let

Mozilla Developer.

let allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. This is unlike the var keyword, which defines a variable globally, or locally to an entire function regardless of block scope.


function varTest() {
  var x = 1;
  if (true) {
    var x = 2;  // same variable!
    console.log(x);  // 2
  }
  console.log(x);  // 2
}

function letTest() {
  let x = 1;
  if (true) {
    let x = 2;  // different variable
    console.log(x);  // 2
  }
  console.log(x);  // 1
}

Use let in for loop:


var list = document.getElementById("list");

for (let i = 1; i <= 5; i++) {
  let item = document.createElement("li");
  item.appendChild(document.createTextNode("Item " + i)); // If "var", i will still be 1-5.

  item.onclick = function (ev) {
    console.log("Item " + i + " is clicked."); // If "var", i will always be 6.
  };
  list.appendChild(item);
}

If you use var here, i in the onclick() function will always be 6.

Create a private interface without using closures:


var SomeConstructor;

{
    let privateScope = {};

    SomeConstructor = function SomeConstructor () {
        this.someProperty = "foo";
        privateScope.hiddenProperty = "bar";
    }

    SomeConstructor.prototype.showPublic = function () {
        console.log(this.someProperty); // foo
    }

    SomeConstructor.prototype.showPrivate = function () {
        console.log(privateScope.hiddenProperty); // bar
    }

}

var myInstance = new SomeConstructor();

myInstance.showPublic();
myInstance.showPrivate();

console.log(privateScope.hiddenProperty); // error

Temporal dead zone

In ECMAScript 2015, let will hoist the variable to the top of the block. However, referencing the variable in the block before the variable declaration results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the declaration is processed.


function do_something() {
  console.log(foo); // ReferenceError
  let foo = 2;
}

const

Mozilla.

The const declaration creates a read-only reference to a value. It does not mean the value it holds is immutable, just that the variable identifier cannot be reassigned. For instance, in case the content is an object, this means the object itself can still be altered.

A common convention is to use all-uppercase letters for const variables.


// define MY_FAV as a constant and give it the value 7
const MY_FAV = 7;

// The following will ALL throw an error:
MY_FAV = 20; // Can't change.
const MY_FAV = 20; // Can't redefine.
// The name MY_FAV is reserved for constant above, so this will also fail
var MY_FAV = 20;
let MY_FAV = 20;

// It's important to note the nature of block scoping
if (MY_FAV === 7) { 
    // this is fine and creates a block scoped MY_FAV variable 
    const MY_FAV = 20;
    // MY_FAV is now 20
    console.log("my favorite number is " + MY_FAV);

    // this gets hoisted into the global context and throws an error
    var MY_FAV = 20;
}

// MY_FAV is still 7
console.log("my favorite number is " + MY_FAV);

// Assigning to A const variable is a syntax error
const A = 1; A = 2;

// throws an error, missing initializer in const declaration
const FOO; 

// const also works on objects
const MY_OBJECT = {"key": "value"};
// Attempting to overwrie the object throws an error
MY_OBJECT = {"OTHER_KEY": "value"};
// However, object keys are not protected, so the following statement is executed without problem
MY_OBJECT.key = "otherValue"; // Use Object.freeze() to make object immutable

// The same applies to arrays
const MY_ARRAY = [];
// It's possible to push items into the array
MY_ARRAY.push("A"); // ["A"]
// However, assigning a new array to the variable throws an error
MY_ARRAY = ["B"]

Destructuring assignment

SO: js es6 const with curly braces.

It is an ES2015 destructuring assignment. It's a syntatically terse way of extracting properties from objects, into variables. It unpacks values from arrays, or properties from objects, into distinct variables. developer.mozilla.org.


// you can rewrite this
const name = app.name;
const version = app.version;
const type = app.type;

// as this
const { name, version, type } = app;

//----------

var a, b, rest;
[a, b] = [10, 20];
console.log(a); // 10
console.log(b); // 20

[a, b, ...rest] = [10, 20, 30, 40, 50];
console.log(a); // 10
console.log(b); // 20
console.log(rest); // [30, 40, 50]

({ a, b } = { a: 10, b: 20 });
console.log(a); // 10
console.log(b); // 20

// Stage 3 proposal
({a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40});
console.log(a); // 10
console.log(b); // 20
console.log(rest); //{c: 30, d: 40}

Best practice

medium.

`const` is a signal that the identifier won’t be reassigned.

`let`, is a signal that the variable may be reassigned, such as a counter in a loop, or a value swap in an algorithm. It also signals that the variable will be used only in the block it’s defined in, which is not always the entire containing function.

`var` is now the weakest, and should be avoided as possible.

typeof is no longer safe

es-discourse.com.



if (condition) {
  console.log(typeof value);     // ReferenceError!
  let value = "blue";
}
typeof x doesn't throw for var x but throws for let x is because var not only creates but also initializes binding to undefined, whereas let merely declares it.

import, export

See "commonjs.note" for more.

http://davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/ amd, commonJs, umd http://stackoverflow.com/questions/16521471/relation-between-commonjs-amd-and-requirejs AMD is more suited for the browser, because it supports asynchronous loading of module dependencies. RequireJS is an implementation of AMD, while at the same time trying to keep the spirit of CommonJS (mainly in the module identifiers). https://zhuanlan.zhihu.com/p/23493436 Prefer yarn than npm.

Importing modules using "require", and exporting using "module.exports" and "exports.foo". Importing modules using ES6 "import", and exporting using ES6 "export".

voidCanvas.com.



//-----CommonJS

//dep.js
dep = {
    foo: function(){},
    bar: 22
}
module.exports = dep;

// app.js
var dep = require("dep");
console.log(dep.bar);
dep.foo();
 
//-----ESM: ECMAScript Modules.

//dep.js
export foo function(){};
export const bar = 22;
 
//app.js
import {foo, bar} from "dep";
console.log(bar);
foo();
 

Rest Parameters

odeToCode.com: features of es6.


let doWork = function(name, ...numbers){
    let result = 0;
     
    numbers.forEach(function(n){
        result += n;
    });
 
    return result;
};

let result = doWork("Scott", 1, 2, 3);
expect(result).toBe(6);

Before ES6, we could use the implicit variable arguments, which is an array-like object, but is not an array, which creates confusion. It is also difficult to spot if a function is using arguments without reading through the code or documentation for the function.

Spread

odeToCode.com: spread.


let doWork = function(x, y, z) {
    return x + y + z;
}
var result = doWork(...[1, 2, 3]);
expect(result).toBe(6);

var a = [4, 5, 6]; 
var b = [1, 2, 3, ...a, 7, 8, 9]; 
expect(b).toEqual([1,2,3,4,5,6,7,8,9]);

Object Rest/Spread Properties for ECMAScript



//----- Rest Properties
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }

//----- Spread Properties
let n = { x, y, ...z };
n; // { x: 1, y: 2, a: 3, b: 4 }

Functions

Generators



function* generator(i) {
  yield i;
  yield i + 10;
}
// returns an Generator object.

var gen = generator(10);

console.log(gen.next().value);
console.log(gen.next().value);
console.log(gen.next().value);

//---------- Output
// 10
// 20
// undefined

Async

An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. But the syntax and structure of your code using async functions is much more like using standard synchronous functions.

An async function can contain an await expression that pauses the execution of the async function and waits for the passed Promise's resolution, and then resumes the async function's execution and returns the resolved value.

Remember, the await keyword is only valid inside async functions.

The purpose of async/await functions is to simplify the behavior of using promises synchronously and to perform some behavior on a group of Promises. Just as Promises are similar to structured callbacks, async/await is similar to combining generators and promises.

javascript.info.



//---------- Async

// returns an AsyncFunction object.
// The word “async” before a function means one simple thing: a function always returns a promise. If the code has return <non-promise> in it, then JavaScript automatically wraps it into a resolved promise with that value.

async function f() {
  return 1;
}
f().then(alert); // 1
//--- We could explicitly return a promise, that would be the same:
async function f() {
  return Promise.resolve(1);
}
f().then(alert); // 1

//---------- Await

// The keyword await makes JavaScript wait until that promise settles and returns its result.

// It’s just a more elegant syntax of getting the promise result than promise.then, easier to read and write.

async function f() {
  let promise = new Promise((resolve, reject) => {
    setTimeout(() => resolve("done!"), 1000)
  });
  let result = await promise; // wait till the promise resolves (*)
  alert(result); // "done!"
}
f();

//---------- Catch

async function f() {
  try {
    let response = await fetch('/no-user-here');
    let user = await response.json();
  } catch(err) {
    // catches errors both in fetch and response.json
    alert(err);
  }
}
f();

//--- Or don’t have try..catch, use .catch instead:

async function f() {
  let response = await fetch('http://no-such-url');
}
// f() becomes a rejected promise
f().catch(alert); // TypeError: failed to fetch

//---------- Promise.all is a nice thing to wait for many tasks simultaneously.

// wait for the array of results
let results = await Promise.all([
  fetch(url1),
  fetch(url2),
  ...
]);

shorthand syntax

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer

// Shorthand property names (ES2015)
var a = 'foo', b = 42, c = {};
var o = {a, b, c};

// Shorthand method names (ES2015)
var o = {
  property([parameters]) {}
};
// Same as
var o = {
  property: function ([parameters]) {},
  get property() {},
  set property(value) {}
};
// In ECMAScript 2015, a shorthand notation is available, so that the keyword "function" is no longer necessary.

// Computed property names (ES2015)
var prop = 'foo';
var o = {
  [prop]: 'hey',
  ['b' + 'ar']: 'there'
};


var obj = {
  foo: function() {
    /* code */
  },
  bar: function() {
    /* code */
  }
};
// You are now able to shorten this to:
var obj = {
  foo() {
    /* code */
  },
  bar() {
    /* code */
  }
};

//---------- Generators

// Using a named property
var obj2 = {
  g: function* () {
    var index = 0;
    while (true)
      yield index++;
  }
};
// The same object using shorthand syntax
var obj2 = { 
  * g() {
    var index = 0;
    while (true)
      yield index++;
  }
};

//---------- Async

// Using a named property
var obj3 = {
  f: async function () {
    await some_promise;
  }
};
// The same object using shorthand syntax
var obj3 = {
  async f() {
    await some_promise;
  }
};

Classes

developer.mozilla.org: Classes.

Defining classes

Classes are in fact "special functions", and just as functions, the class syntax has two components: class expressions and class declarations.

Class declarations



class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

Hoisting

An important difference between function declarations and class declarations is that function declarations are hoisted and class declarations are not. You first need to declare your class and then access it, otherwise code will throw a ReferenceError.

Class expressions

A class expression is another way to define a class.



// unnamed
let Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
// output: "Rectangle"

// named
let Rectangle = class Rectangle2 {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};
console.log(Rectangle.name);
// output: "Rectangle2"

Class expressions are subject to the same hoisting restrictions as described in the Class declarations section.

Class body

The body of a class is executed in strict mode.

Static methods

Static methods are called without instantiating their class and cannot be called through a class instance.



class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  static distance(a, b) {
    const dx = a.x - b.x;
    const dy = a.y - b.y;

    return Math.hypot(dx, dy);
  }
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.distance(p1, p2)); // 7.0710678118654755

Static class-side properties and prototype data properties

Static class-side properties and prototype data properties must be defined outside of the ClassBody declaration:


Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;