Summary of ways to implement inheritance features in JavaScript programs

  • 2021-06-29 10:13:45
  • OfStack

Summary
All objects of JavaScript have their own chain of inheritance.That is, each object inherits another object, called an "prototype" (prototype) object.Except for null, it does not have its own prototype object.

The importance of the prototype object is that if the A object is the prototype of the B object, then the B object can get all the properties and methods of the A object.The Object.getPrototypof method is used to get the prototype object of the current object.


var p = Object.getPrototypeOf(obj);

In the code above, the object p is the prototype object of the object obj.

The Object.create method is used to generate a new object that inherits the specified object.


var obj = Object.create(p);

In the code above, the prototype of the newly generated obj object is the object p.

Nonstandard_uproto_uProperties (two underscores each) that override an object's prototype object.However, this property should be used as little as possible, but instead, read and write prototype objects using Object.getPrototypeof() and Object.setPrototypeOf().


var obj = {};
var p = {};

obj.__proto__ = p;
Object.getPrototypeOf(obj) === p // true

The above code passes through uproto_uProperty that makes the p object the prototype of the obj object.

Here is a practical example.


var a = {x: 1};
var b = {__proto__: a};
b.x // 1

In the code above, the b object passes through uproto_uProperty sets your own prototype object as an a object, so the b object gets all the properties and methods of the a object.The b object itself does not have an x attribute, but the JavaScript engine passes through uproto_uProperty, find its prototype object a, and read the x property of a.

The new command creates a new instance object through a constructor, essentially by binding the prototype of the instance object to the prototype property of the constructor, and then executing the constructor on the instance object.


var o = new Foo();

//  Equivalent to 
var o = new Object();
o.__proto__ = Foo.prototype;
Foo.call(o);

Prototype object's own_uproto_uAttributes can also point to other objects to form a prototype chain (prototype chain) at level 1.


var a = { x: 1 };
var b = { __proto__: a };
var c = { __proto__: b };

c.x // 1

It is important to note that looking up an attribute in the prototype chain level 1 has an impact on performance.The higher the prototype object is looking for, the greater the impact on performance.If you look for an attribute that does not exist, you will traverse the entire prototype chain.

Action Point of this
Wherever this is defined, it always points to the current object, not the prototype object, when used.


var o = {
 a: 2,
 m: function(b) {
  return this.a + 1;
 }
};

var p = Object.create(o);
p.a = 12;

p.m() // 13

In the code above, the m method of the p object comes from its prototype object, o.At this point, the this object inside the m method does not point to o, but to p.

Inheritance of constructors
This section describes how to have one constructor inherit another.

Suppose you have an Shape constructor.


function Shape() {
 this.x = 0;
 this.y = 0;
}

Shape.prototype.move = function (x, y) {
 this.x += x;
 this.y += y;
 console.info('Shape moved.');
};
Rectangle Constructor Inheritance Shape . 

function Rectangle() {
 Shape.call(this); //  Call parent class constructor 
}
//  another 1 Seed Writing 
function Rectangle() {
 this.base = Shape;
 this.base();
}

//  Subclass inherits method of parent class 
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

rect instanceof Rectangle // true
rect instanceof Shape // true

rect.move(1, 1) // 'Shape moved.'

The code above indicates that the inheritance of a constructor is divided into two parts, one part is that the subclass calls the parent's construction method, and the other part is that the prototype of the subclass points to the parent's prototype.

In the code above, the subclass is the overall inheritance parent.Sometimes, only the inheritance of a single method is required, and the following can be used.


ClassB.prototype.print = function() {
 ClassA.prototype.print.call(this);
 // some code
}

In the code above, the print method of the subclass B calls the print method of the parent A before deploying its own code.This is equivalent to inheriting the print method of the parent A.

_uproto_uattribute
_uproto_uThe property points to the prototype object of the current object, the prototype property of the constructor.


var obj = new Object();

obj.__proto__ === Object.prototype
// true
obj.__proto__ === obj.constructor.prototype
// true

The code above first creates a new object, obj, whose uproto_uProperty that points to the prototype property of the constructor (Object or obj.constructor).So, after comparing the two, return to true.

Therefore, there are three ways to get the prototype object of the instance object obj.

obj.__proto__ obj.constructor.prototype Object.getPrototypeOf(obj)

None of the above three methods are reliable.Latest ES6 Standard Provisions, uproto_uProperty only browsers need to be deployed, other environments can not be deployed.obj.constructor.prototype may fail when manually altering a prototype object.


var obj = Object.create(p);
0

In the code above, the prototype object of the C constructor was changed to p, resulting in distorted c.constructor.prototype.Therefore, when changing the prototype object, 1 generally sets the constructor property at the same time.


C.prototype = p;
C.prototype.constructor = C;

c.constructor.prototype === p // true

Therefore, the third Object.getPrototypeOf method is recommended for obtaining prototype objects.This method is used as follows.


var o = new Object();

Object.getPrototypeOf(o) === Object.prototype
// true

You can use the Object.getPrototypeOf method to check if your browser supports_uproto_uProperty, which is not supported by older browsers.


var obj = Object.create(p);
3

The code above will u of an objectproto_uSet the property to null and use the Object.getPrototypeOf method to get the prototype of this object to determine if it is equal to null.If the current environment supports uproto_uAttribute, the result of comparison should be true.

With uproto_uProperty makes it easy to prototype an instance object.Suppose you have three objects, machine, vehicle, and car, of which machine is the prototype of vehicle and vehicle is the prototype of car, which can be set in two lines of code.


var obj = Object.create(p);
4

Here's an example, through uproto_uAttribute and constructor.prototype attributes read the attributes defined on the prototype object, respectively.


var obj = Object.create(p);
5

Obviously, uproto_uIt looks a little more concise.

When an instance object is generated from a constructor, the u of the instance objectproto_uProperty automatically points to the constructor's prototype object.


var obj = Object.create(p);
6

Inheritance of attributes
There are two types of attributes.One is the object's native property, the other is the inherited property inherited from the prototype.

Native Properties of Objects
All properties of the object itself can be obtained using the Object.getOwnPropertyNames method.


Object.getOwnPropertyNames(Date)
// ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"]

Among the properties of the object itself, some are enumerable (enumerable) and some are not.Get only those properties that can be enumerated, using the Object.keys method.


Object.keys(Date) // []
hasOwnProperty()

The hasOwnProperty method returns a Boolean value that determines whether an attribute is defined on the object itself or on the prototype chain.


var obj = Object.create(p);
9

The hasOwnProperty method does not traverse the prototype chain when only 11 of the JavaScript methods handle object properties.

Inheritance Properties of Objects
Objects created with the Object.create method inherit the properties of all prototype objects.


var proto = { p1: 123 };
var o = Object.create(proto);

o.p1 // 123
o.hasOwnProperty("p1") // false

Get all properties
Use the in operator to determine whether an object has an attribute, whether it is self-contained or inherited.


"length" in Date // true
"toString" in Date // true

To get all the enumerable properties of an object, whether self or inherited, you can use the for-in loop.


var o1 = {p1: 123};

var o2 = Object.create(o1,{
 p2: { value: "abc", enumerable: true }
});

for (p in o2) {console.info(p);}
// p2
// p1

In order to get the properties of the object itself in the for...in loop, the hasOwnProperty method can be used to judge 1.


for ( var name in object ) {
 if ( object.hasOwnProperty(name) ) {
  /* loop code */
 }
}

To get all the properties of an object, whether self or inherited, and enumerable, you can use the following functions.


function inheritedPropertyNames(obj) {
 var props = {};
 while(obj) {
  Object.getOwnPropertyNames(obj).forEach(function(p) {
   props[p] = true;
  });
  obj = Object.getPrototypeOf(obj);
 }
 return Object.getOwnPropertyNames(props);
}

The usage is as follows:


inheritedPropertyNames(Date)
// ["caller", "constructor", "toString", "UTC", "call", "parse", "prototype", "__defineSetter__", "__lookupSetter__", "length", "arguments", "bind", "__lookupGetter__", "isPrototypeOf", "toLocaleString", "propertyIsEnumerable", "valueOf", "apply", "__defineGetter__", "name", "now", "hasOwnProperty"]

Copy of object
If you want to copy an object, you need to do the following two things.

Ensure that the copied object has the same prototype prototype object as the original object.
Ensure that the copied object has the same properties as the original object.
Here are the functions for copying objects based on the above two points.


function copyObject(orig) {
 var copy = Object.create(Object.getPrototypeOf(orig));
 copyOwnPropertiesFrom(copy, orig);
 return copy;
}

function copyOwnPropertiesFrom(target, source) {
 Object
 .getOwnPropertyNames(source)
 .forEach(function(propKey) {
  var desc = Object.getOwnPropertyDescriptor(source, propKey);
  Object.defineProperty(target, propKey, desc);
 });
 return target;
}

multiple inheritance
JavaScript does not provide multiple inheritance, that is, it does not allow one object to inherit multiple objects at the same time.However, this can be achieved through workarounds.


function M1(prop) {
 this.hello = prop;
}

function M2(prop) {
 this.world = prop;
}

function S(p1, p2) {
 this.base1 = M1;
 this.base1(p1);
 this.base2 = M2;
 this.base2(p2);
}
S.prototype = new M1();

var s = new S(111, 222);
s.hello // 111
s.world // 222

In the code above, the subclass S inherits both the parent M1 and M2.Of course, from the inheritance chain, S has only one parent, M1, but since M1 and M2 constructors are executed simultaneously on the instance of S, it inherits both methods.


Related articles: