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:
- Var _this = {};
- [[prototype]] of _this points to the Constructor’s prototype, that is, _this.proto = constructive.prototype
- Change Constructor’s this to _this and execute Constructor, i.e. Constructor.apply(_this,agrs); Get the constructed _this object
- 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:
- Everything is an object (js has primitive types, functional first class objects)
- Objects are copied from other objects (in the JS Object world, everything starts with the Object. Prototype egg)
- An object remembers its prototype (in JS an object’s __proto__ property points to its prototype)
- 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:
-
Object instance inherits from a class (constructor)
-
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.