ES6 class

Prior to the RELEASE of ES6, JavaScript didn’t have the traditional object-oriented language of class writing. When ES6 was released, Babel quickly followed suit, and developers quickly embraced the new programming experience of ES6. Of course, in this confusing and subtle language, many of the things we see every day are often overlooked. For ES6 syntax, we will convert the code to ES5 for browser compatibility. However, why did previous ES versions emulate ES6 features such as class and inheritance,super,static? What changes has JavaScript made to address these new roles? This article will explore the operation mechanism of class instance construction, class inheritance relationship, super keyword and static keyword. The level is limited, if there is confusion or mistakes in the article, please also point out.

Class instance construction

Class Basic example

Basically, the ES6 class form is as follows:

 class Whatever{
      
 }
Copy the code

B: Of course, we can use the constructor method.

class Whatever{ constructor(){ this.name = 'hahaha'; }}Copy the code

Please refer to the corresponding version of ES5:

function Whatever{
    this.name = 'hahaha';
}
Copy the code

What did New do

Constructor corresponds to the previous behavior in the constructor. In the case of the ES5 constructor, when called by new, there are roughly four steps:

  1. Var _this = {};
  2. [[prototype]] of _this points to the Constructor’s prototype, that is, _this.proto = constructive.prototype
  3. Change Constructor’s this to _this and execute Constructor, i.e. Constructor.apply(_this,agrs); Get the constructed _this object
  4. Check the value returned by Constructor, _this if the value is not a reference type, or a modified reference object otherwise

So, constructor instances inherit methods mounted on Prototype. In ES6 calSS, we’ll mount methods on class Prototype:

class Whatever{ //... methodA(){ //... }}Copy the code

Corresponding to ES5:

function Whatever{
    this.name = 'hahaha';
}
Whatever.prototype = function methodA(){
            //...
        }
Copy the code

Class inheritance

Basic features of prototype language

In prototype-based languages, there are four characteristics:

  1. Everything is an object (js has primitive types, functional first class objects)
  2. Objects are copied from other objects (in the JS Object world, everything starts with the Object. Prototype egg)
  3. An object remembers its prototype (in JS an object’s __proto__ property points to its prototype)
  4. When calling properties/methods that the object does not have, the object tries to delegate to its prototype

You should see why methods mounted on constructive. prototype are “inherited” by instances! In the ES6 class, the inheritance relationship is still maintained by [[prototype]].

Child.prototype.__proto__ === Parent.prototype;
Child.__proto__ === Parent;
childObject.__proto === Child.prototype;
Copy the code

When the arrow function collides with class

The arrow function in ES6 was loved from the get-go because it solved the “problem” of dynamically pointing to this during function execution (why quotes? Because sometimes we do need the great convenience that dynamic this brings. The arrow function binds this to the lexical scope where it is defined:

//ES6:
const funcArrow = () => {
    //your code
}
//ES5:
var _this = this;
var funcArrow = function(){
    this = _this;
    //your code
}
Copy the code

Some children may think, since js inheritance and this is so important, calSS use the word binding this arrow function, what would happen? Let’s see.

class WhateverArrow{ // methodArrow = () => { //... }}Copy the code

How will this be different from the writing above?

class WhateverNormal{ // methodNormal() { //... }}Copy the code

Let’s take a look at the prototype differences between the two constructors in chrome:

WhateverArrow. Prototype listing: class Whatever1 __proto__: Object WhateverNormal. Prototype listing: constructor Class Whatever2 methodNormal: ƒ methodNormal() __proto__: ObjectCopy the code

In light of the above discussion on prototyping, taste the differences between the two and try it out manually.

Method and function type attributes

We call the form func(){} “method” and methodArrow = () =>:any! Methods are mounted in Prototype; properties are not. The methodArrow attribute is assigned to this in the constructor:

this.methodArrow = function methodArrow(){
    this = _this;
    //any code
}
Copy the code

When the instance calls methodArrow, it calls its own methodArrow instead of the calss WhateverArrow. Prototype method.

 var WhateverArrow = function WhateverArrow() {
  var _this = this;

  _classCallCheck(this, WhateverArrow);

  _defineProperty(this, "methodArrow", function () {
    consoe.log(_this);
  });
};
Copy the code

Extends,super and [[HomeObject]]

Let’s extend

When we talk about inheritance, we tend to mean two things:

  1. Object instance inherits from a class (constructor)

  2. Subclasses inherit from their parent class. We looked at the first type above. Now, turn your attention to the second type. Consider the following code:

    class Parent { constructor(){ this.tag = ‘A’; this.name = ‘parent name’ } methodA(){ console.log(‘methodA in Parent’) } methodB(){ console.log(this.name); }}

    class Child extends Parent{ constructor(){ super(); This this.name = ‘child name’} methodA(){super.methoda (); console.log(‘methodA in Child’) } } const c1 = new Child(); c1.methodA(); //methodA in Parent // methodA in Child

We use extends to connect two classes, indicating that they are “parent” classes. The subclass method blocks methods with the same name in the parent class. Unlike Java polymorphism, the number of method parameters does not affect whether the method is the same or not. In Child’s constructor, this must be called after super(), otherwise an error will be reported as this is undefined. The reason is simply that when new is performed, the _this of Child comes from the constructor that called Parent; if super() is not called,_this will be undefined. Those who are interested in this problem can try it out by themselves and think about it with Babel’s transformation results.

Where does super come from? What is the [[HomeObject]] object?

What did Super do

Super allows us to borrow properties and methods from the parent class in our subclasses.

 methodA(){
            super.methodA();
            console.log('methodA in Child')
        }
Copy the code

Super keyword is really a genius idea to promote father-son bond! MethodA (); methodA(); methodA(); methodA();

Where does super come from? How to invite super, the great immortal?

MethodA: Parent: prototype.methodA: Parent: prototype.methodA: Parent: prototype.methodA: Parent: prototype.methodA We know:

Child.prototype.__proto__ === Parent.prototype;
cs.__proto__ === Child.prototype;
c1.methodA();
Copy the code

When c1. MethodA () is executed, methodA refers to c1. If so, consider the following code:

Class GrandFather{methodA(){console.log('methodA in GrandFather')}} class Parent extends GrandFather{ methodA(){ super.methodA(); console.log('methodA in Parent') } } class Child extends Parent{ methodA(){ super.methodA(); console.log('methodA in Child') } }Copy the code

Consider that we are now the execution engine, we find c1 through this, and then we find child.prototype. methodA through prototype; In child.prototype.methoda we have super.methoda (); Now we’re going to go to super, which is Parent. Parent.prototype.methodA; this.proto.__proto__methoda; For parent.prototype. methodA, use the same method as for c1. Prototype. methodA (); The problem is that when parent.prototype. methodA is run, this still points to c1. Isn’t it an endless cycle? Obviously, trying to find super through this is just going to get you nowhere.

[[HomeObject]] came out of nowhere

To deal with super, the JS engine simply makes methods (methods, not properties) hardbind to the [[HomeObject]] property at creation time, pointing to the object to which they belong! MethodA ([[HomeObject]]); methodA ([[HomeObject]]); At this point, according to [[HomeObject]], you can find the super! When Babel is converted to ES5, the reference to super is hardcoded. The same idea is to hardbind the object (object or function) to which the current method belongs:

_createClass(Parent, [{key: "methodA", value: Function methodA() {super.methoda (); _get(_getPrototypeOf(Parent. Prototype), "methodA", this).call(this); console.log('methodA in Parent');}}]);Copy the code

Note the difference between attributes and methods:

Var obj1 = {__proto__:SomePrototype, methodQ(){//methodQ is bound to [[HomeObject]]->obj1; }} var obj2 = {__proto__: methodQ:function(){// not bind any [[HomeObject]] super.somemethod (); / / Syntax Eroor! Syntax error: super is not allowed to be called on non-methods of objects}}Copy the code

The arrow function then attacks super

In light of the previous discussion about the arrow function inside the class, we have to ask a question: where does the arrow function in the class refer to super? Consider the following code:

class Parent{       
    methodA(){       
       console.log('methodA in Parent')
    }       
}
    
class Child extends Parent{
    methodA = () => {
       super.methodA();
       console.log('methodA in Child')
    }
}

const c1 = new Child();
c1.methodA();
Copy the code

The output is:

methodA in Parent
methodA in Child
Copy the code

There seems to be no surprise. We need to update asynchron and change the Parent methodA method to the arrow function:

class Parent{       
    methodA = () => {       
       console.log('methodA in Parent')
    }       
}
    
class Child extends Parent{
    methodA = () => {
       super.methodA();
       console.log('methodA in Child')
    }
}

const c1 = new Child();
c1.methodA();
Copy the code

I’m sorry to say that this has happened:

Uncaught TypeError: (intermediate value).methodA is not a function
    at Child.methodA 
Copy the code

How to change methodA to a normal method function in Child?

class Parent{       
    methodA = () => {       
       console.log('methodA in Parent')
    }       
}
    
class Child extends Parent{
    methodA () {
       super.methodA();
       console.log('methodA in Child')
    }
}

const c1 = new Child();
c1.methodA();
Copy the code

Output:

MethodA in Parent // Does not print methodA in ChildCopy the code

The reasons for the above results please combine the previous chapters carefully taste, you will have a harvest.

Static that cannot be ignored

The static performance of the

Simply put, the static keyword marks a property or method that is mounted to the class itself and can be accessed via classname. staticMethod.

class Child{ static name = '7788'; static methodA () { console.log('static methodA in Child') } } Child.name; / / 7788; Child.methodA(); //static methodA in ChildCopy the code

How is static passed to subclasses

Proto ===Parent static: [[prototype]] static: [[prototype]]

class Parent{ static methodA () { console.log('static methodA in Parent') } } class Child extends Parent{ } Child.methodA(); //static methodA in ParentCopy the code

Super is accessed in the static method

class Parent{ static methodA () { console.log('static methodA in Parent') } } class Child extends Parent{ static methodA  () { super.methodA() console.log('static methodA in Child') } } Child.methodA(); //static methodA in Parent //static methodA in ChildCopy the code

conclusion

JS is a magic language, magic to many people tend to use JS but not JS(… Hh). As a popular and constantly improving language, it has many confusing aspects due to its time and historical legacy. It’s easy to overlook the mechanics of some of the features we face every day. Even if you think you understand it one day, later on you may encounter another problem and suddenly realize that you still know too little (and too young). And then dig deep to understand, after a period of time may again… Perhaps the course that studies JS is the progress of such spiral type. Thanks to Babel, she’s really useful for us to understand how some of the JS features work, because Babel really knows JS inside and out. . Her “translation” of ES6 can help us understand the new ES6 features as well as previous versions of JS. Writing in a hurry, inevitably there are mistakes and omissions, welcome to point out. I wish you all good health and fewer bugs.