3

kind

Classes are templates for creating objects. The method of generating object instances in JavaScript is through the constructor, which is quite different from mainstream object-oriented languages (java, C#) in writing, as follows:

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

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 1);

ES6 provides a way of writing closer to the Java language, introducing the concept of Class as a template for objects. Through the class keyword, you can define a class.

As follows: constructor() is the construction method, and this represents the instance object:

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

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

The data type of the class is the function, which itself is the constructor that points to the function:

// ES5 函数声明
function Point() {
    //...
}

// ES6 类声明
class Point {
  //....
  constructor() {
  }
}
typeof Point // "function"
Point === Point.prototype.constructor // true

The method defined in the class is linked to Point.prototype , so the class only provides syntactic sugar, and the essence is the prototype chain call.

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

  toString() {
    return '(' + this.x + ', ' + this.y + ')';
  }
}

Point.prototype = {
  //....
  toString()
}
var p = new Point(1, 1);
p.toString() // (1,1)

Another way to define a Class expression

// 未命名/匿名类
let Point = class {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
};
Point.name // Point

There is an important difference between function declarations and class declarations. Function declarations will be promoted, while class declarations will not be promoted.

let p = new Point(); // 被提升不会报错
function Point() {}

let p = new Point(); // 报错,ReferenceError
class Point {}

constructor()

constructor() method is the default method of the class. new will automatically call this method when the instance object is generated.

A class must have the constructor() method. If it is not explicitly defined, the engine will add an empty constructor() by default.

constructor() method returns the instance object by default (ie this ).

class Point {
}

// 自动添加
class Point {
  constructor() {}
}

getter and setter

get and set can be used inside the class to set the value function and the value function of a certain attribute to intercept the access behavior of the attribute.

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

  get name() {
    return this.name;
  }

  set name(value) {
    this.name = value;
  }
}

this

this inside the method of the class, it defaults to the instance of the class. When calling this , you need to use the obj.method() method, otherwise an error will be reported.

class User {
  constructor(name) {
    this.name = name;
  }
  printName(){
    console.log('Name is ' + this.name)
  }
}
const user = new User('jack')
user.printName() // Name is jack
const { printName } = user;
printName()     // 报错 Cannot read properties of undefined (reading 'name')

If you want to call it alone without bind(this) an error, a method can be called 06177612b7055b in the constructor.

class User {
  constructor(name) {
    this.name = name;
    this.printName = this.printName.bind(this);
  }
  printName(){
    console.log('Name is ' + this.name)
  }
}
const user = new User('jack')
const { printName } = user;
printName()     // Name is jack
bind(this) will create a new function and use the incoming this as the context of the function when it is called.

You can also use arrow functions, because the this inside the arrow function always points to the object where it was defined.

class User {
  constructor(name) {
    this.name = name;
  }
  printName = () => {
    console.log('Name is ' + this.name)
  }
}
const user = new User('jack')
const { printName } = user;
printName()     // Name is jack

Static properties

Static attributes refer to the attributes of the class itself, not the attributes defined on the instance object this .

class User {
}

User.prop = 1;
User.prop // 1

Static method

You can define a static method in the class, the method will not be inherited by the object instance, but directly through the class to call.

The use of this in the static method refers to the class.

class Utils {
  static printInfo() {
     this.info();
  }
  static info() {
     console.log('hello');
  }
}
Utils.printInfo() // hello

Regarding the limitation of the calling range of the method, such as: private public, ES6 does not provide it for the time being, it is generally through an agreement, such as: adding an underscore _print() in front of the method to indicate a private method.

inherit

In Java, class inheritance extends ES6 classes can also be inherited extends

When inherited, the subclass must constructor call method super method, otherwise it will error when creating a new instance.

class Point3D extends Point {
  constructor(x, y, z) {
    super(x, y); // 调用父类的constructor(x, y)
    this.z = z;
  }

  toString() {
    return super.toString() + '  ' + this.z ; // 调用父类的toString()
  }
}

The static methods of the parent class will also be inherited by the child class.

class Parent {
  static info() {
    console.log('hello world');
  }
}

class Child extends Parent {
}

Child.info()  // hello world

super keyword

The constructor of the subclass must execute the super function once, which represents the constructor of the parent class.

class Parent {}

class Child extends Parent {
  constructor() {
    super();
  }
}

When calling the method of the parent class super ordinary method of the this inside the method points to the current instance of the subclass.

class Parent {
  constructor() {
    this.x = 1;
    this.y = 10
  }
  printParent() {
    console.log(this.y);
  }
  print() {
    console.log(this.x);
  }
}

class Child extends Parent {
  constructor() {
    super();
    this.x = 2;
  }
  m() {
    super.print();
  }
}

let c = new Child();
c.printParent() // 10
c.m() // 2

_proto_ and prototype

When you first _proto_ JavaScript, 06177612b709ba and prototype are easy to confuse. First of all, we know that each JS object corresponds to a prototype object, and inherits properties and methods from the prototype object.

  • prototype some built-in objects and functions. It is a pointer to an object. The purpose of this object is to include the properties and methods shared by all instances (we call this object the prototype object).
  • _proto_ Each object has this attribute, which generally points to the prototype attribute of the corresponding constructor.

The picture below shows some built-in objects prototype

According to the above description, look at the following code

var obj = {} // 等同于 var obj = new Object()

// obj.__proto__指向Object构造函数的prototype
obj.__proto__ === Object.prototype // true 

// obj.toString 调用方法从Object.prototype继承
obj.toString === obj.__proto__.toString // true

// 数组
var arr = []
arr.__proto__ === Array.prototype // true 

For function objects, each function declaration also has prototype and __proto__ properties, object properties created __proto__ point function prototype , function __proto__ in turn points to the built-in function object (Function) of prototype .

function Foo(){}
var f = new Foo();
f.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true

Inheriting __proto__

Class as a syntactic sugar for the constructor, there will also be prototype attributes and __proto__ attributes, so there are two inheritance chains at the same time.

  1. __proto__ attribute of the subclass indicates the inheritance of the constructor and always points to the parent class.
  2. The prototype attribute of the __proto__ attribute indicates the inheritance of the method and always points to the prototype attribute of the parent class.
class Parent {
}

class Child extends Parent {
}

Child.__proto__ === Parent // true
Child.prototype.__proto__ === Parent.prototype // true

Inherit the __proto__

__proto__ attribute of the subclass instance prototype subclass construction method.

Examples of subclass __proto__ attribute __proto__ attributes, points to the parent class instance __proto__ properties. In other words, the prototype of the prototype of the child class is the prototype of the parent class.

class Parent {
}

class Child extends Parent {
}

var p = new Parent();
var c = new Child();

c.__proto__ === p.__proto__ // false
c.__proto__ === Child.prototype // true
c.__proto__.__proto__ === p.__proto__ // true

summary

Class in JavaScript is more syntactic sugar, and essentially cannot bypass the prototype chain. Welcome everyone to leave a message and exchange.


编程码农
455 声望1.4k 粉丝

多年编程老菜鸟👨‍💻🦍