Deep Understanding of ES6 - Knowledge of JS Classes

Keywords: Javascript REST Programming Attribute

Basic class declarations

Class declarations begin with the class keyword, followed by the class name; the rest of the grammar looks like method abbreviations in object literals, and commas are not required between methods.

class Person {
    //Constructor equivalent to prototype
    constructor(name) {
        this.name = name;
    }

    SayName() {
        console.log(this.name);
    }
}

let per = new Person("cf");
per.SayName();//cf

console.log(typeof Person);//function

The greatest use of a constructor is to perform initialization when creating an object, and when creating an object, the system defaults to initialization for an instance of that object. If you want to change this default initialization, you can do it through a custom constructor.

The Difference between Classes and Custom Types

  1. Class declarations will not be promoted. Class declarations behave like let, so classes exist in a temporary dead zone before the execution of the program reaches the declaration.
  2. All code in class declarations automatically runs in strict mode and cannot exit from strict mode.
  3. All methods of a class are not enumerable
  4. There is no [[Construct]] in all methods of a class, so using new to call them throws errors.
  5. Calling a class constructor without using new throws an error.
  6. An attempt to override the class name inside the class throws an error.

Classes are similar to functions in that they have two forms: declaration and expression.

Basic class expressions

let PersonClass = class {
    constructor(name) {
        this.name = name;
    }

    SayName() {
        console.log(this.name);
    }
}

let per = new PersonClass("cc");
per.SayName();

Class expressions and class declarations are not promoted

Named class expression

let PersonClass = class PersonClass2 {
    constructor(name) {
        this.name = name;
    }

    SayName() {
        console.log(this.name);
        console.log(PersonClass2);
    }
}

let per = new PersonClass("cc");
per.SayName();

The class expression in this example is named PersonClass2.PersonClass2 only exists inside the class definition, so it can only be used inside the class method.

As well as the category of citizens

In programming, a first-class citizen can be used as a value, which means that he can be used as a parameter, as a function return value, and as a variable assignment. The function of js is first-class citizen.

let createObject = function (classDef) {
    return new classDef();
}

let obj = new createObject(class {
    SayHi() {
        console.log("hi");
    }
})

obj.SayHi();

Owned attributes need to be created in class constructors, and classes allow you to define accessor attributes on prototypes. To create a getter, use the get keyword and leave a space between it and the rear identifier; create a setter in the same way, just use the set keyword instead

class CustomHtmlElement {
    constructor(element) {
        this.element = element;
    }
    get html() {
        return this.element.innerHTML;
    }

    set html(value) {
        this.element.innerHTML = value;
    }
}

Membership to be calculated

Class methods and class accessor attributes can also use names that need to be computed. The grammar is the same as the computational name in the literal quantity of an object: instead of using an identifier, an expression is wrapped in square brackets

let methodName = "SayName";
class PersonClass {
    constructor(name) {
        this.name = name;
    }

    [methodName]() {
        console.log(this.name);
    }
}

let per = new PersonClass("cc");
per.SayName();

Generator Method

Symbol.iterator can be used to define generator methods to define default iterators for classes.

class Collection {
    constructor() {
        this.items = [];
    }

    *[Symbol.iterator]() {
        yield this.items;
    }
}

let collection = new Collection();

collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for (let num of collection.items) {
    console.log(num);
}

Static member

Static members cannot be accessed by instances, and you always need to access them directly by the class itself.

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

    SayName() {
        console.log(this.name);
    }

    static create() {
        return new PersonClass(name);
    }
}

let per = new PersonClass.create("cc");

Inheritance using derived classes

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

    getArea() {
        return this.length * this.width;
    }
}

class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }
}

let sq = new Square(10);
console.log(sq.getArea());//100

Classes that inherit other classes are called derived classes. If a derived class specifies a constructor, you need to use super(), otherwise you will make an error. If the constructor is not defined, the super() method is automatically invoked and all the parameters provided when creating a new instance are used. For example:

class Square extends Rectangle {

}

let sq = new Square(10, 10);
console.log(sq.getArea());//100

The following points need to be kept in mind when using super

  1. You can only use super in derived classes.
  2. In the constructor, you must call super() before accessing this. Since super() is responsible for initializing this, an attempt is made to access this first and then report an error.
  3. The only way to avoid calling super() is to return an object from the class constructor.

Shielding class method

Methods in derived classes always shield the same-name methods of base classes. For example, you can add the getArea() method to the Square class to redefine its functionality.

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

    getArea() {
        return this.length * this.width;
    }
}

class Square extends Rectangle {
    constructor(length, name) {
        super(length, length);
        this.name = name;
    }

    getArea() {
        return `this is ${this.name} input ${this.length}`
    }
}

You can also use the super.getArea() method to call the same-name method in the base class.

class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }

    getArea() {
        return super.getArea();
    }
}

Inheriting static members

If the base class contains static members, these static members are also available in derived classes.

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

    getArea() {
        return this.length * this.width;
    }

    static create(length, width) {
        return new Rectangle(length, width);
    }
}
      
        
class Square extends Rectangle {
    constructor(length) {
        super(length, length);
    }
}
let sqr = Square.create(10, 10);

console.log(sqr.getArea());//100

Derivation of classes from expressions

Perhaps the most powerful ability to derive classes in ES6 is to derive classes from expressions. As long as an expression can return a function with [[Constructor]] attributes and prototypes, you can use extends on it.

function Rectangle(length,width){
    this.length = length;
    this.width = width;
}

Rectangle.prototype.getArea = function(){
    return this.length * this.width;
}

class Square extends Rectangle{
    constructor(length){
        super(length,length);
    }
}
let x = new Square(10);

console.log(x.getArea());//100

The ability to accept any type of expression after extends brings great possibilities, such as dynamically determining the class to inherit.

function Rectangle(length, width) {
    this.length = length;
    this.width = width;
}

Rectangle.prototype.getArea = function () {
    return this.length * this.width;
}

function getBase() {
    return Rectangle;
}

class Square extends getBase() {
    constructor(length) {
        super(length, length);
    }
}

let x = new Square(10);

console.log(x.getArea());

Any expression can be used after the extends keyword, but not all expressions result in a valid class.

  1. null
  2. generator function

Inheritance of built-in objects

In the inheritance of class ES6, the value of this is first created by the base class and then modified by the constructor of the derived class. The result is that this initially has all the functions of a built-in object as a base class and can correctly receive all the functions associated with it.

class MyArray extends Array {

}

let arr = new MyArray();
arr[0] = 'red';
console.log(arr.length);

arr.length = 0;
console.log(arr[0]);

Symbol.species attribute

An interesting aspect of inheriting built-in objects is that any method that can return instances of built-in objects automatically returns instances of derived classes.

class MyArray extends Array {

}

let arr = new MyArray(1, 2, 3);
let subitems = arr.slice(1, 2);
console.log(subitems);

Posted by padma on Thu, 16 May 2019 11:11:39 -0700