This is the second day of my participation in Gwen Challenge

Class class

Es6 introduced the concept of the class class as a template for objects. The class keyword defines a class. Es6 classes can be thought of as just another way of writing constructors.

class Point {
  // ...
}

typeof Point // "function"
Point === Point.prototype.constructor // true
Copy the code

As you can see from the above code, the data type of a class is a function, and the class itself points to a constructor.

The new command is used directly on the class, as is the case with constructors.

All methods of a class are defined on the prototype property of the class.

All methods defined inside a class are non-enumerable.

The constructor method

The constructor() method is the default method of the class and is automatically called when an object instance is generated using the new command.

A class must have a constructor() method; if it is not explicitly defined, an empty constructor() method is added by default.

The constructor() method returns the instance object (that is, this) by default; you can specify that another object should be returned.

class Foo {
  constructor() {
    return Object.create(null); }}new Foo() instanceof Foo
// false
Copy the code

In the above code, manually changing the return value of the constructor method results in an instance object that is not an instance of class Foo.

Instances of the class

As in ES5, the attributes of an instance are defined on the stereotype (class) unless they are explicitly defined on themselves (that is, on this object). Take a look:

/ / define the class
class Point {

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

  toString() {
    return '(' + this.x + ', ' + this.y + ') '; }}var point = new Point(2.3);

point.toString() / / (2, 3)

point.hasOwnProperty('x') // true
point.hasOwnProperty('y') // true
point.hasOwnProperty('toString') // false
point.__proto__.hasOwnProperty('toString') // true
Copy the code

In the above code, attributes X, y are defined on this, and this refers to the instance object itself, so hasOwnProperty() returns true and toString() is the property of the prototype object (because it is defined on the Point class), So the hasOwnProperty() method returns false.

All instances of the class share a stereotype object.

var p1 = new Point(2.3);
var p2 = new Point(3.2);

p1.__proto__ === p2.__proto__
Copy the code

Attribute expression

Just look at the code:

let methodName = 'getArea';

class Square {
  constructor(length) {
    // ...
  }

  [methodName]() {
    // ...}}Copy the code

The expressions of the class

Like functions, classes can be defined in the form of expressions

const MyClass = class Me {
  getClassName() {
    returnMe.name; }};Copy the code

The above code defines a class using an expression. Note that the name of this Class is Me, but Me is only available inside the Class and refers to the current Class. Outside of Class, this Class can only be referenced by MyClass.

let inst = new MyClass();
inst.getClassName() // Me
Me.name // ReferenceError: Me is not defined
Copy the code

Using the class expression, you can also write a class that executes immediately

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

  sayName() {
    console.log(this.name);
  }
}('Joe');

person.sayName(); // "/"
Copy the code

PS: Points of attention

  • Inside classes and modules, strict mode is the default.
  • Class does not have a hoist, which means that a class must be defined before it can be called with new.
  • The value of the name attribute is the name of the class itself.class Point {} Point.name // "Point".
  • Class methods that contain this inside point to instances of the class by default. You must be careful, however, that you may get an error if you use this method alone.
class Logger {
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text); }}const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
Copy the code

In the code above, this in the printName method points to an instance of the Logger class by default. However, if we extract this method and use it alone, this will refer to the environment in which the method was run (because the class is in strict mode, so this actually refers to undefined), and we will fail to find print.

There are two common ways to solve this problem: bind and arrow functions. These are the two ways we use to define the method binding to this in the React class.

class Logger {
  constructor() {
    this.printName = this.printName.bind(this);
    this.getThis = () = > this;
  }

  // ...
}
Copy the code

Class static methods

A class is the prototype of an instance, and all methods defined in a class are inherited by the instance. However, if you prefix a method with the static keyword, it means that the method is not inherited by the instance, but is called directly from the class. This is called a “static method.” PS: If a static method contains the this keyword, this refers to the class, not the instance. Static methods can have the same name as non-static methods.

Static methods of a parent class can be inherited by subclasses.

class Foo {
  static classMethod() {
    return 'hello'; }}class Bar extends Foo {
    Static methods can also be called from super objects.
    static classMethod() {
        return super.classMethod() + ', too';
    }
}

Bar.classMethod() // 'hello'
Copy the code

The way a class attribute is defined

class foo {
  bar = 'hello';
  baz = 'world';
  constructor() {
    this.x = 'abc'}}Copy the code

Static attributes

Static properties refer to properties of the Class itself, class.propName, not properties defined on the instance object (this).

class Foo {
    static myStaticProp = 42;
}

Foo.prop = 1;
Foo.prop / / 1
Copy the code

The above code, written in two different ways, defines a static property prop and myStaticProp for class Foo.

The new target attribute

New is the command to generate the instance object from the constructor. ES6 introduces a new.target attribute for the new command, which is typically used in constructors to return the constructor on which the new command is applied. If the constructor is not called with the new command or reflect.construct (), new.target returns undefined, so this property can be used to determine how the constructor is called.

function Person(name) {
  if (new.target ! = =undefined) {
    this.name = name;
  } else {
    throw new Error('Instance must be generated using the new command'); }}// Another way to write it
function Person(name) {
  if (new.target === Person) {
    this.name = name;
  } else {
    throw new Error('Instance must be generated using the new command'); }}var person = new Person('Joe'); / / right
var notAPerson = Person.call(person, 'Joe');  / / an error
Copy the code

The above code ensures that the constructor can only be called with the new command.

Class calls new.target internally to return the current Class.

class Rectangle {
  constructor(length, width) {
    console.log(new.target === Rectangle);
    this.length = length;
    this.width = width; }}var obj = new Rectangle(3.4); / / output true
Copy the code

Note that when a subclass inherits from its parent, new.target returns the subclass.

class Shape {
  constructor() {
    if (new.target === Shape) {
      throw new Error('This class cannot be instantiated'); }}}class Rectangle extends Shape {
  constructor(length, width) {
    super(a);// ...}}var x = new Shape();  / / an error
var y = new Rectangle(3.4);  / / right
Copy the code

In the above code, the Shape class cannot be instantiated and can only be used for inheritance.

Note that outside the function, using new.target raises an error.