The content this article brings to you is about the implementation principles (code examples) of ES6 classes and inheritance. It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.
1. es6 class uses
javascript uses prototypal inheritance. We can achieve class inheritance through the characteristics of prototypes.
es6 is We provide syntactic sugar like object-oriented inheritance.
class Parent { constructor(a){ this.filed1 = a; } filed2 = 2; func1 = function(){} } class Child extends Parent { constructor(a,b) { super(a); this.filed3 = b; } filed4 = 1; func2 = function(){} }
Let’s use babel to explore the implementation principles of es6 classes and inheritance.
1. Class implementation
Before conversion:
class Parent { constructor(a){ this.filed1 = a; } filed2 = 2; func1 = function(){} }
After conversion:
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var Parent = function Parent(a) { _classCallCheck(this, Parent); this.filed2 = 2; this.func1 = function () { }; this.filed1 = a; };
It can be seen that the bottom layer of class is still the constructor:
1. Call the _classCallCheck method to determine whether there is a new keyword before the current function call.
If the new keyword is used before the constructor is executed, an empty object will be created inside the constructor, the proptype of the constructor will point to the _proto_ of the empty object, and this will point to the empty object. As above, in _classCallCheck: this instanceof Parent returns true.
If there is no new in front of the constructor, the proptype of the constructor will not appear on the prototype chain of this, and false will be returned.
2. Assign the variables and functions inside the class to this.
3. Execute the internal logic of constuctor.
4.return this (the constructor is done at the end by default).
Before conversion:
class Child extends Parent { constructor(a,b) { super(a); this.filed3 = b; } filed4 = 1; func2 = function(){} }
After conversion:
Let’s first look at the internal implementation of Child, and then look at the internal calls How to implement the function:
var Child = function (_Parent) { _inherits(Child, _Parent); function Child(a, b) { _classCallCheck(this, Child); var _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, a)); _this.filed4 = 1; _this.func2 = function () {}; _this.filed3 = b; return _this; } return Child; }(Parent);
1. Call the _inherits function to inherit the proptype of the parent class.
_inherits internal implementation:
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
(1) Verify the parent constructor.
(2) Typical parasitic inheritance: Create an empty object using the proptype of the parent class constructor and point this object to the proptype of the subclass constructor.
(3) Point the parent constructor to the _proto_ of the child constructor (it is not clear what this step does, and it feels meaningless.)
2. Use a closure The package saves the parent class reference and does the subclass construction logic inside the closure.
3.new check.
4. Use the current this to call the parent class constructor.
var _this = _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).call(this, a));
Child.__proto__ || Object.getPrototypeOf(Child) is actually the parent constructor (the last operation of _inherits), and then changes its caller to the current this through call and passes parameter. (I feel like you can directly use the Parent passed in as a parameter here)
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
Verify whether this has been initialized, whether super has been called, and return this that has been assigned by the parent class.
5. Assign the variables and functions inside the row subclass to this.
6. Execute the logic inside the subclass constuctor.
It can be seen that es6 actually provides us with a simple way of writing "combined parasitic inheritance".
super represents the parent class constructor.
super.fun1() is equivalent to Parent.fun1() or Parent.prototype.fun1().
super() is equivalent to Parent.prototype.construtor()
When we do not write a subclass constructor:
var Child = function (_Parent) { _inherits(Child, _Parent); function Child() { _classCallCheck(this, Child); return _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).apply(this, arguments)); } return Child; }(Parent);
It can be seen that the default constructor will be actively called The parent class constructor, and by default passes the parameters passed by the current constructor to the parent class.
So when we declare the constructor, we must actively call super(), otherwise the parent constructor cannot be called and the inheritance cannot be completed.
A typical example is in Reatc's Component. We must call super(props) after declaring the constructor, because the parent class needs to do some initialization operations on props in the constructor.
The above is the detailed content of Implementation principles of ES6 classes and inheritance (code examples). For more information, please follow other related articles on the PHP Chinese website!