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 two
obj
: 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
- Parameters of a
-
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:
- It is not appropriate to instantiate Animal when the Dog constructor and prototype are created.
- Dog’s constructor cannot call Animal’s constructor, resulting in a duplicate assignment of the name property in the Dog constructor.
- 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).
- An error pointing to the constructor property in the implementation.
- 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