Basic use of class in ES6

  • There are several keywords used:

    • Class: used to define ‘classes’;
    • Constructor: used to initialize the ‘class’;
    • Extends: extends a subclass from its parent;
    • Super: Calls the superclass method
      • Constructor: call super() directly and pass the constructor argument, which is equivalent to calling the parent constructor;
      • In ordinary methods (prototype methods), super refers to the prototype object of the parent class and calls super.xx(), where xx refers to a method of the parent class.
  • Sample code:

    // Base class - animal
    class Animal {
        constructor(name) {
            this.name = name;
        }
        sayName() {
            console.log(this.name, 'methods in -------- base class >>>>>>>>Animal'); }}let animal = new Animal('Critters');
    animal.sayName();
    
    // Subclass, dog -- derived from animal class
    class Dog extends Animal {
        constructor(name, age) {
            super(name);
            this.age = age;
        }
        sayName() {
            // Call the parent method
            super.sayName();
            // Write the subclass's own methods
            console.log(`The ${this.name}(The ${this.age})---------- subclass >>>>>>>>>>>Dog method '); }}let dog = new Dog('rhubarb'.'7');
    dog.sayName();
    
    Copy the code

    Is it simple? Is it surprising? Is it unexpected?

    Class usage is that simple, but knowing that this is just syntactic sugar, how does inheritance work in ES5?

The basic implementation of inheritance in ES5

  • The use of several keywords:

    • Function: Classes are created using functions;
    • Prototype: prototype attribute;
    • Object.create(__proto__.obj) : used to create objects
      • Parameters of a__proto__: required, the prototype object of the object being created.
      • Parameters of the twoobj: Optional, a JavaScript object containing one or more property descriptors that specify properties to be added to the object. It can be divided into two categories, data properties and accessor properties
  • Simple use of sample code (thinking about how to call parent methods from the basic example) :

    // Base class - animal
    function Animal(name) {
        this.name = name;
    }
    
    Animal.prototype.sayName = function() {
        console.log(this.name, 'methods in -------- base class >>>>>>>>Animal');
    }
    
    // Subclass, dog -- derived from animal class
    function Dog(name, age) {
        this.name = name;
        this.age = age;
    }
    
    // Point the Dog prototype to an instance of Animal
    Dog.prototype = new Animal();
    // Since an instance of Animal can call the methods of the Animal prototype, an instance of Dog can also call all properties of the Animal prototype.
    Dog.prototype.sayName = function(argument) {
        console.log(`The ${this.name}(The ${this.age})---------- subclass >>>>>>>>>>>Dog method ');
    }
    var dog = new Dog('rhubarb'.'7');
    dog.sayName();
    Copy the code

What are the similarities and differences between es6Class creation and function creation in ES5?

  • Similarities:

    • There are declarations and expressions
    • Name and length are treated the same
    • Create variable results are consistent ***
    • Fn can use call,apply.bind to change this
  • Difference:

    • Declaratively, fn in ES5 has variable promotion, class in ES6 does not
    • Dog class, fn creation can be called with call, class creation cannot
    • The Dog class is created globally. Fn can access Dog in the window, but class generation cannot

So how did developers write class inheritance before ES6 came out? Don’t be naive, people are not that stupid, other already encapsulated implementation of such methods.

When looking at ES5, how else does inheritance work

// Base class - animal
var Animal = Class.extend({
    // init is a constructor that acts as contructor
    init: function(name) {
        this.name = name;
    },
    sayName: function() {
        console.log(this.name, 'methods in -------- base class >>>>>>>>Animal'); }});var animal = new Animal('Critters');
animal.sayName();

// Subclass, dog -- derived from animal class
var Dog = Animal.extend({
    // init is a constructor
    init: function(name, age) {
        // Call the parent constructor in the constructor
        this._super(name);
        this.age = age;
    },
    sayName: function() {
        // Call the parent method
        this._super();
        // Write the subclass's own methods
        console.log(`The ${this.name}(The ${this.age})---------- subclass >>>>>>>>>>>Dog method '); }});var dog = new Dog('rhubarb'.'7');
dog.sayName();
Copy the code

After seeing how others use inheritance, let’s implement a similar manual implementation of prototype inheritance

  • For example, look at basic inheritance

    // Base class - animal
    function Animal(name) {
        this.name = name;
    }
    
    Animal.prototype.sayName = function() {
        console.log(this.name, 'methods in -------- base class >>>>>>>>Animal');
    }
    // Subclass, dog -- derived from animal class
    function Dog(name, age) {
        this.name = name;
        this.age = age;
    }
    
    // Point the Dog prototype to an instance of Animal
    Dog.prototype = new Animal();
    // Since an instance of Animal can call the methods of the Animal prototype, an instance of Dog can also call all properties of the Animal prototype.
    Dog.prototype.sayName = function() {
        console.log(`The ${this.name}(The ${this.age})---------- subclass >>>>>>>>>>>Dog method ');
    }
    var dog = new Dog('rhubarb'.'7');
    dog.sayName();
    Copy the code
  • Drawbacks of the above example:

    1. It is not appropriate to instantiate Animal when the Dog constructor and prototype are created.
    2. Dog’s constructor cannot call Animal’s constructor, resulting in a duplicate assignment of the name property in the Dog constructor.
    3. The Dog function overrides the Animal function with the same name. There is no mechanism for overloading (same type of problem as the previous one).
    4. An error pointing to the constructor property in the implementation.
    5. A single responsibility is not universal enough.
  • We worked through it one defect at a time and ended up with the package structure we wanted. Here’s the complete code

    var Class = (function() {
      // Identifies whether the initialization of the class is complete, and if so, calls init to initialize the constructor
      var initCompleteStatus = false;
      // Define the re, and complete strings bounded by _super are true
      var reg = /\b_super\b/;
    
      function parentClass() {} // Parent, initialize base class is empty object
    
      parentClass.extend = function(props) {
        function childClass() {
          if (initCompleteStatus) {
            this.init.apply(this.arguments); }}var _super = this.prototype; // The prototype of the parent class
        // Save all attributes of the parent as the prototype of the subclass and reset constructor
          
        initCompleteStatus = false;
        // The instantiation at this point does not call init
        childClass.prototype = new this(a); initCompleteStatus =true;
          
        Object.defineProperty(childClass.prototype, "constructor", {
          value: childClass
        });
        
        // The assignment of its own attribute
        for (var name in props) {
          if (typeof props[name] === "function" && reg.test(props[name])) {
            childClass.prototype[name] = (function(name, fn) {
              return function() {
                console.dir(Object.toString.call(fn));
                var temp = this._super;
                this._super = _super[name];
                // Get the function return value
                var result = fn.apply(this.arguments);
                this._super = temp;
                // Return the value
                return result;
              };
            })(name, props[name]);
          } else {
            childClass.prototype[name] = props[name];
          }
        }
        childClass.extend = arguments.callee;
        return childClass;
      };
      returnparentClass; }) ();Copy the code