ES6 Basics 1

A glimpse at some common ES6 features.

Arrow Function

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.

Basic syntax(be aware of the last case):

1
2
3
4
5
6
7
8
9
10
(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
// equivalent to: => { return expression; }

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

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

Comment:

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

See this example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person() {
// The Person() constructor defines `this` as an instance of itself.
this.age = 0;

setInterval(function growUp() {
// In non-strict mode, the growUp() function defines `this`
// as the global object (because it's where growUp() is executed.),
// which is different from the `this`
// defined by the Person() constructor.
this.age++;
}, 1000);
}

var p = new Person();

Traditional (ES3, ES5) solutions:

1
2
3
4
5
6
7
8
9
10
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);
}

Or we could use bind()function.

ES6 solution:
An arrow function does not have its own this; the this value of the enclosing execution context is used. Thus, in the following code, the this within the function that is passed to setInterval has the same value as this in the enclosing function:

1
2
3
4
5
6
7
8
9
function Person(){
this.age = 0;

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

var p = new Person();

Addition:

  1. Arrow functions do not have a prototype property.
  2. The yield keyword may not be used in an arrow function’s body (except when permitted within functions further nested within it). As a consequence, arrow functions cannot be used as generators.

Class

JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript’s existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript.

Define a class

  1. Class Declaration:

    1
    2
    3
    4
    5
    6
    class Rectangle {
    constructor(height, width) {
    this.height = height;
    this.width = width;
    }
    }
  2. Class expressions

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    // 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"

Strict mode in Class

Code within the class syntax is always executed in strict mode, see this example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}

let obj = new Animal();
obj.speak(); // Animal {}
let speak = obj.speak;
speak(); // undefined

Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined

What will happen in traditional mode?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Animal() { }

Animal.prototype.speak = function() {
return this;
}

Animal.eat = function() {
return this;
}

let obj = new Animal();
let speak = obj.speak;
speak(); // global object

let eat = Animal.eat;
eat(); // global object

Explanation:
Autoboxing in method calls will happen in non–strict mode based on the initial this value. If the inital value is undefined, this will be set to the global object.

Autoboxing will not happen in strict mode, the this value remains as passed.

Sub classing with extends

Basic example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Animal {
constructor(name) {
this.name = name;
}

speak() {
console.log(this.name + ' makes a noise.');
}
}

class Dog extends Animal {
constructor(name) {
super(name); // call the super class constructor and pass in the name parameter
}

speak() {
console.log(this.name + ' barks.');
}
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

If there is a constructor present in subclass, it needs to first call super() before using “this”.

Addition:
The only purpose of extends is to create single-ancestor class taxonomies.

let and const

The let statement declares a block scope local variable, optionally initializing it to a value.

1
2
3
4
5
6
7
8
9
10
11
let x = 1;

if (x === 1) {
let x = 2;

console.log(x);
// expected output: 2
}

console.log(x);
// expected output: 1

let is an alternative to Javascript’s traditional scoping rules

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.

Constants are block-scoped, much like variables defined using the let statement. The value of a constant cannot change through re-assignment, and it can’t be redeclared.

1
2
3
4
5
6
7
8
9
10
11
12
const number = 42;

try {
number = 99;
} catch(err) {
console.log(err);
// expected output: TypeError: invalid assignment to const `number'
// Note - error messages will vary depending on browser
}

console.log(number);
// expected output: 42