ES6 – Classes

 · 5 mins read

Defining classes

The class declaration creates a new class with a given name using prototype-based inheritance.

You can also define a class using a class expression. But unlike the class expression, the class declaration doesn’t allow an existing class to be declared again and will throw a type error if attempted.

Classes are in fact “special functions”, and just as you can define function expressions and function declarations, the class syntax has two components: class expressions and class declarations.

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

Hoisting

Editor’s Note: Hoisting means like Evaluating

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 like the following will throw a ReferenceError:

var p = new Rectangle(); // ReferenceError

class Rectangle {}

Class body and method definitions

Strict mode

The bodies of class declarations and class expressions are executed in strict mode i.e. constructor, static and prototype methods, getter and setter functions are executed in strict mode.

Constructor

The constructor method is a special method for creating and initializing an object created with a class. There can only be one special method with the name “constructor” in a class. A SyntaxError will be thrown if the class contains more than one occurrence of a constructor method.

A constructor can use the super keyword to call the constructor of a parent class.

Prototype methods

Static methods

The static keyword defines a static method for a class. Static methods are called without instantiating their class and cannot be called through a class instance. Static methods are often used to create utility functions for an application.

class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
  // Getter
  get area() {
    return this.calcArea();
  }
  // Method
  calcArea() {
    return this.height * this.width;
  }

  //static method
  static definition(){
      return "A rectangle is a four-sided flat shape where every angle is a right angle (90°). "
  }
}

Boxing with prototype and static methods

When a static or prototype method is called without an object valued “this”, then the “this” value will be undefined inside the called function. Autoboxing will not happen. The behavior will be the same even if we write the code in non-strict mode because all the functions, methods, constructor, getters or setters are executed in strict mode. So if we do not specify this value then the this value will be undefined.

Editor’s Note:

Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes. For example, converting an int to an Integer, a double to a Double, and so on. If the conversion goes the other way, this is called unboxing.

Sub classing with extends

class Animal { 
  constructor(name) {
    this.name = name;
  }

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

class Dog extends Animal {
  constructor(name,age) {
    //If there is a constructor present in sub-class, it needs to first call super() before using "this".
    super(name);
    this.age = age;
  }

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

var d = new Dog('Mitzie',12);
d.speak(); // Mitzie, 12, barks.

Note that classes cannot extend regular (non-constructible) objects. If you want to inherit from a regular object, you can instead use Object.setPrototypeOf():

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

class Dog {
  constructor(name) {
    this.name = name;
  }
}

Object.setPrototypeOf(Dog.prototype, Animal);// If you do not do this you will get a TypeError when you invoke speak

var d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.

Species

You might want to return Array objects in your derived array class MyArray. The species pattern lets you override default constructors.

For example, when using methods such as map() that returns the default constructor, you want these methods to return a parent Array object, instead of the MyArray object. The Symbol.species symbol lets you do this:

class MyArray extends Array {
  // Overwrite species to the parent Array constructor
  static get [Symbol.species]() { return Array; }
}

var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array);   // true

Mix-ins

Editor’s Note

In object-oriented programming languages, a Mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes. How those other classes gain access to the mixin’s methods depends on the language. Mixins are sometimes described as being “included” rather than “inherited”.

Abstract subclasses or mix-ins are templates for classes. An ECMAScript class can only have a single superclass, so multiple inheritance from tooling classes, for example, is not possible. The functionality must be provided by the superclass.

A function with a superclass as input and a subclass extending that superclass as output can be used to implement mix-ins in ECMAScript:

var calculatorMixin = Base => class extends Base {
  calc() { }
};

var randomizerMixin = Base => class extends Base {
  randomize() { }
};

A class that uses these mix-ins can then be written like this:

class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

Have you understood?

Let me explain this, firstly I will rewrite it in ECMA5 version

<br />var calculatorMixin = function (Base){
    return class extends Base {
        calc() {
            console.log("calc")
        }
    }
}

var randomizerMixin = function (Base){
    return class extends Base {
        randomize(){
            console.log("randomize")
        }
    }
}



class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

var b = new Bar()
b.calc()        //calc
b.randomize();  //randomize


LINKS:

classes-MDN

Class 的基本语法

Class 的继承