preface
In javascript, instance objects are generated by creating a function and instantiating the function object as new. This scheme is very different from traditional language and can easily confuse people. Es6 provides a more traditional language version: class. However, class can be thought of as syntactic sugar, and ES5 can do most of what it does. Let’s explore how class is implemented in ES5.
Written es6
class A {
constructor(name) {
this.name = name;
}
say() {
console.log(this.name); }}class B extends A {
constructor() {
super();
}
}
Copy the code
Here we define two classes, A and B, and B inherits from A.
Next, we get the following code under Babel escape
var A = /*#__PURE__*/ (function () {
function A(name) {
_classCallCheck(this, A);
this.name = name;
}
_createClass(A, [
{
key: 'say'.value: function say() {
console.log(this.name); }},]);returnA; }) ();var B = /*#__PURE__*/ (function (_A) {
_inherits(B, _A);
var _super = _createSuper(B);
function B() {
_classCallCheck(this, B);
return _super.call(this);
}
return B;
})(A);
Copy the code
As you can see, class is actually implemented by function
Class implementation principles
Let’s look at the implementation of class through A
First, variable A is assigned A self-executing function that returns internally defined function A, so variable A is A function.
Then, in addition to the instance assignment, _classCallCheck(this,A) is called internally.
function _classCallCheck(instance, Constructor) {
if(! _instanceof(instance, Constructor)) {// same as! (this instanceof A)
throw new TypeError('Cannot call a class as a function'); }}Copy the code
That is, if you do not call the function with the new keyword, this instanceof A will be false, return true, and raise the exception. This is why class cannot be executed directly as a function.
_createClass
Next, after the function is created, the _createClass function is called. This function passes two values. The first is function A, and the second is an array containing the function say defined in class A.
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
function _defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ('value' in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor); }}Copy the code
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
Copy the code
through_createClass
We’re going to do that_defineProperties
Constructor is the function A, so the first argument is equal to a.prototype and the second argument is the array holding the say function
This is done by iterating through an array of functions and storing the corresponding function to target (a.protoType) with Object.defineProperty
Finally, function A is assigned function A, and function A’s prototype has say
Principle of inheritance
var B = /*#__PURE__*/ (function (_A) {
_inherits(B, _A);
var _super = _createSuper(B);
function B() {
_classCallCheck(this, B);
return _super.call(this);
}
return B;
})(A);
Copy the code
As you can see, B is A self-executing function, just like A, but B takes one argument, which is function A
The self-executing function of B first executes _inherits(B, _A)
function _inherits(subClass, superClass) {
if (typeofsuperClass ! = ='function'&& superClass ! = =null) {
throw new TypeError('Super expression must either be null or a function');
}
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: { value: subClass, writable: true.configurable: true}});if (superClass) _setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf =
Object.setPrototypeOf ||
function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
Copy the code
Here, first let b.prototype._proto_ = a.prototype and constructor point to B. Next, execute _setPrototypeOf, making B._proto = A.
So, _inherits is to construct A prototype chain between B and A
super
Next, create super
var _super = _createSuper(B);
function _createSuper(Derived) {
var hasNativeReflectConstruct = _isNativeReflectConstruct();
return function _createSuperInternal() {
var Super = _getPrototypeOf(Derived),
result;
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototypeOf(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
result = Super.apply(this.arguments);
}
return _possibleConstructorReturn(this, result);
};
}
function _isNativeReflectConstruct() {
if (typeof Reflect= = ='undefined' || !Reflect.construct) return false;
if (Reflect.construct.sham) return false;
if (typeof Proxy= = ='function') return true;
try {
Date.prototype.toString.call(Reflect.construct(Date[],function () {}));
return true;
} catch (e) {
return false; }}function _possibleConstructorReturn(self, call) {
if (call && (_typeof(call) === 'object' || typeof call === 'function')) {
return call;
}
return _assertThisInitialized(self);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError(
"this hasn't been initialised - super() hasn't been called"
);
}
return self;
}
Copy the code
Reflect is the new ES6 operation object API, in order to determine whether Reflect can be used, use Reflect. Let’s ignore Reflect and go straight to Reflect’s unusable logic
var Super = _getPrototypeOf(Derived) // Get the prototype of Derived B
result = Super.apply(this.arguments); // Call A, passing this instance and arguments
Copy the code
As you can see, _createSuper returns A function that executes the prototype of the current function, which executes A. That is, inheritance by borrowing constructors. This is why subclasses must call the super method from the constructor method, because their own this object must first be molded by the parent class’s constructor to get the same instance properties and methods as the parent class.
Will end by _possibleConstructorReturn judge whether the execution of the parent function returns an object, if is an object, finally returned to the parent () function returns the object.
conclusion
These are basically the principles of ES6 inheritance.
The first time to write an article, write not good, please forgive, if there is a problem in the article, welcome to comment, I will correct in time.