Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to understand JavaScript inheritance

2025-03-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article will explain in detail how to understand JavaScript inheritance, the content of the article is of high quality, so the editor will share it for you as a reference. I hope you will have a certain understanding of the relevant knowledge after reading this article.

Background

Inheritance provides us with an elegant and reusable coding method, and inheritance is also a question that is often asked in interviews. This article comprehensively summarizes the inheritance types in JavaScript, the advantages and disadvantages of each inheritance type and the usage scenarios. Read through JavaScript inheritance, so put it away.

Prototype inheritance

Prototype chain is the main method to realize prototype inheritance. The basic idea is to use the prototype to make one reference type inherit the properties and methods of another reference type.

Implement the basic pattern of the prototype chain

Function SuperType () {this.property=true;} SuperType.prototype.getSuperValue=function () {returnthis.property;} function SubType () {this.subproperty=false;} SubType.prototype=new SuperType (); SubType.prototype.getSubValue=function () {returnthis.property;}; var instance=new SubType (); console.log (instance.getSuperValue ()); / / true

The example in the example and the relationship diagram between the constructor and the prototype:

In the example code, two objects, subType and superType, are defined.

Inheritance is implemented between the two objects, which is achieved by creating an instance of SuperType and assigning that instance to subType.prototype. The essence of implementation is to rewrite the prototype object.

There will be a pointer to the prototype object of the superType in the subType.prototype. That is, the properties and methods in the instance that exist in superType now exist in subType.prototype. After this inheritance, you can add new methods and properties for subType.

Note that this pointer ([[prototype]]) is no longer externally accessible by default, and is expected to be used by some internal methods, such as finding the object inherited by the current object when using for...in to traverse properties that can be enumerated on the prototype chain. However, Firefox, Safari, and Chrome support an attribute of _ _ proto__ on each object.

Some problems that should be paid attention to in prototype inheritance

1. Don't forget the default type

We know that all reference types inherit Object, and this inheritance is also implemented through the prototype chain. So all objects have some of the default methods that Object has. Such as: hasOwnProperty (), propertyIsEnumerable (), toLocaleString (), toString () and valueOf ()

two。 To determine the relationship between prototype and instance, the relationship between prototype and instance can be determined in two ways.

① uses the instanceof operator, which is used to test constructors that have appeared in the instance and prototype chain, and the result returns true.

The second way to ② is to use the isPrototypeOf () method. Similarly, as long as the prototype appears in the prototype chain, it can be said to be the prototype of the instance derived from the prototype chain, so the isPrototypeOf () method also returns true.

Example:

Alert (instance instanceofObject); / true alert (instance instanceof SuperType); / / true alert (instance instanceof SubType); / / true alert (Object.prototype.isPrototypeOf (instance)); / / true alert (SuperType.prototype.isPrototypeOf (instance)); / / true alert (SubType.prototype.isPrototypeOf (instance)); / / true

The ③ subclass defines a new method after inheritance

Because prototype inheritance is essentially rewriting prototype objects. So, if you define some methods and properties on the prototype of the subclass before inheriting. Then when inheriting, these properties and methods of the subclass will be overridden.

As shown in the figure:

④ cannot use object literals to create prototype methods

The principle of this is actually the same as that of the third point. When you use the object literal prototype method to rewrite the prototype, it is essentially rewriting the prototype chain, so the original prototype chain is cut off. As shown in the figure:

⑤ pay attention to situations where the parent class contains reference types

As shown in the figure:

The SuperType constructor in this example defines a colors property that contains an array (reference type value). Each instance of SuperType has its own colors property that contains its own array. When SubType inherits SuperType through the prototype chain, SubType.prototype becomes an instance of SuperType, so it also has its own colors property-just as it specifically created a SubType.prototype.colors property. But what was the result? The result is that all instances of SubType share this colors property. Our changes to instance1.colors can be reflected through instance2.colors. That is, such a change will affect each instance.

Shortcomings of prototype inheritance (problems)

Hongmeng official Strategic Cooperation to build HarmonyOS Technology Community

The most obvious is the ⑤ point above. When there is a reference type, the operation of each instance on that reference will affect other instances.

There is no way to pass parameters to a supertype constructor without affecting all object instances.

In view of this, prototype inheritance is rarely used alone in practice.

Borrow constructor inheritance

In solving the problem of including reference type values in prototypes, developers began to use a technique called borrowing constructors (constructor stealing) (sometimes called forgery objects or classical inheritance). The basic idea of this technique is quite simple, that is, calling the supertype constructor inside the subtype constructor.

Basic mode

Function SuperType () {this.colors = ["red", "blue", "green"];} function SubType () {/ / inherits SuperType SuperType.call (this);} var instance1 = new SubType (); instance1.colors.push ("black"); alert (instance1.colors); / / "red,blue,green,black" var instance2 = new SubType (); alert (instance2.colors); / / "red,blue,green"

Basic thought

The basic idea of borrowing constructors is to use call or apply to copy (borrow) the properties and methods specified by this in the parent class to the instance created by the subclass. Because this objects are bound at run time based on the execution environment of the function. That is, globally, this equals window, and when a function is called as a method of an object, this equals that object. The call and apply methods can be used to call a method instead of another object. The call and apply methods change the object context of a function from the initial context to the new object specified by thisObj.

So, this borrowing constructor is when the new object (note that the new operator is different from the direct call, when the function is called directly, when the this points to the window,new creation, the this points to the created instance), creates a new instance object and executes the code in the SubType, while the SubType calls SuperTyep with call, which means that the this is changed to point to the new instance. So the this-related properties and methods in SuperType will be assigned to the new instance instead of to SupType. All instances have these this properties and methods defined by the parent class.

advantage

Compared with the prototype chain, borrowing the constructor has a great advantage, that is, you can pass parameters to the supertype constructor in the subtype constructor. Because the property is bound to the this, it is assigned to the corresponding instance when it is called, and the values of each instance will not affect each other.

For example:

Function SuperType (name) {this.name = name;} function SubType () {/ / inherits SuperType and passes the parameter SuperType.call (this, "Nicholas"); / / instance property this.age = 29;} var instance = new SubType (); alert (instance.name); / / "Nicholas"; alert (instance.age); / / 29

Inferior position

If you just borrow the constructor, you can't avoid the problem with the constructor pattern-- the methods are defined in the constructor, so function reuse is out of the question. Also, the methods defined in the supertype prototype are not visible to the subtypes, and as a result all types can only use the constructor pattern. Given these problems, techniques for borrowing constructors are rarely used alone.

Combinatorial inheritance

Combinatorial inheritance (combination inheritance) is sometimes called pseudo-classical inheritance. It is an inheritance mode that combines the techniques of prototype chain and borrowing constructor together to give full play to the advantages of both.

Basic thought

The idea is to use the prototype chain to inherit the prototype properties and methods, and to inherit the instance properties by borrowing the constructor. In this way, function reuse is realized by defining methods on the prototype, and each instance can be guaranteed to have its own properties.

Basic model

Function SuperType (name) {this.name = name; this.colors = ["red", "blue", "green"];} SuperType.prototype.sayName = function () {alert (this.name);}; function SubType (name, age) {/ / inheritance attribute SuperType.call (this, name); this.age = age;} / / inheritance method SubType.prototype = new SuperType (); SubTypeSubType.prototype.constructor = SubType SubType.prototype.sayAge = function () {alert (this.age);}; var instance1 = new SubType ("Nicholas", 29); instance1.colors.push ("black"); alert (instance1.colors); / / "red,blue,green,black" instance1.sayName (); / / "Nicholas"; instance1.sayAge (); / / 29 var instance2 = new SubType ("Greg", 27); alert (instance2.colors) / / "red,blue,green" instance2.sayName (); / / "Greg"; instance2.sayAge (); / / 27

advantage

Combinatorial inheritance avoids the defects of prototype chain and borrowing constructor, combines their advantages, and becomes the most commonly used inheritance mode in JavaScript.

Inferior position

The biggest problem with combinatorial inheritance is that in any case, the supertype constructor is called twice: once when the subtype prototype is created, and once inside the subtype constructor. Although the subtype will eventually contain all the instance properties of the supertype object, we have to override these properties when calling the subtype constructor.

Parasitic inheritance

Prototype inheritance

The principle is that with the help of prototypes, new objects can be created based on existing objects. Saves the step of creating custom types (though it doesn't make much sense).

Model

Function object (o) {function W () {} W.prototype = o; returnnew W ();}

ES5 added the Object.create () method to standardize prototype inheritance. That is, the calling method is: Object.create (o)

Applicable scenario

You can use Object.create () when you only want one object to establish an inheritance relationship with another object; if this method is not compatible, add it manually to be compatible.

Parasitic inheritance

Parasitic inheritance is an enhanced version of prototype inheritance.

Model

Function createAnother (origin) {var clone=object (origin); clone.say=function () {alert ('hi')} return clone;}

That is, after generating the object that inherits the parent class, add some enhancements to the object.

Parasitic combinatorial inheritance

In essence, parasitic combinatorial inheritance is an enhanced version of parasitic inheritance. This is also the best way to avoid calling the parent constructor twice in combinatorial inheritance. Therefore, developers generally believe that parasitic combinatorial inheritance is the most ideal inheritance paradigm for reference types.

Basic mode

Function inheritPrototype (SubType,SuperType) {var prototype=object (SuperType.prototype); prototype.constructor=subType; subType.prototype=prototype;}

This object is a custom function equivalent to the Object.create () method in ES5. You can write both in terms of compatibility.

Compatible writing method

Function object (o) {function W () {} W. prototypewriter; returnnew W;} function inheritPrototype (SubType,SuperType) {var prototype; if (typeofObject.create==='function') {prototype=Object.create (SuperType.prototype);} else {prototype=object.create (SuperType.prototype);}

Prototype.constructor=SubType; SubType.prototype=prototype;}

Class inheritance

Class can inherit through the extends keyword. The subclass must call the super method in the constructor method, otherwise it will report an error when creating a new instance. This is because the this object of the subclass must first be molded through the constructor of the parent class to get the same instance properties and methods as the parent class, and then process it, plus the subclass's own instance properties and methods. If you do not call the super method, the subclass will not get the this object.

Note: the essence of ES5 inheritance is to create an instance object of the subclass this, and then add the methods of the parent class to the this (Parent.apply (this)). The inheritance mechanism of ES6 is completely different. The essence is to add the properties and methods of the instance object of the parent class to this (so you must call the super method first), and then modify the this with the constructor of the subclass.

Class ColorPoint extends Point {constructor (x, y, color) {super (x, y); / / call parent class constructor (x, y) this.color = color;} toString () {returnthis.color +'+ super.toString (); / / call parent class toString ()}}

The inheritance chain of Class

In the ES5 implementation of most browsers, each object has a _ _ proto__ attribute that points to the prototype property of the corresponding constructor. As the syntax sugar of the constructor, Class has both the prototype attribute and the _ _ proto__ attribute, so there are two inheritance chains at the same time.

(1) the _ _ proto__ attribute of the subclass, which represents the inheritance of the constructor, always points to the parent class.

(2) the _ _ proto__ attribute of the prototype attribute of the subclass, which represents the inheritance of the method, and always points to the prototype attribute of the parent class.

Class A {} class B extends A {} B. protoplast _ = = A / / true B.prototype.protoplast _ = A.prototype / / true

In the above code, the _ _ proto__ attribute of subclass B points to parent class A, and the _ _ proto__ attribute of subclass B's prototype attribute points to the prototype attribute of parent class A.

On how to understand JavaScript inheritance to share here, I hope that the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report