Home  >  Article  >  Web Front-end  >  Summary of 9 inheritance implementation methods in JavaScript_javascript skills

Summary of 9 inheritance implementation methods in JavaScript_javascript skills

WBOY
WBOYOriginal
2016-05-16 15:58:30993browse

Unlike class-based programming languages ​​such as C and Java, inheritance in JavaScript is prototype-based. At the same time, because JavaScript is a very flexible language, there are many ways to implement inheritance.

The first basic concept is about constructors and prototype chains. The constructor of the parent object is called Parent, the constructor of the child object is called Child, and the corresponding parent and child objects are parent and child respectively.

There is a hidden attribute [[prototype]] (note not prototype) in the object. In Chrome it is __proto__, but in some environments it is inaccessible. It points to the prototype of this object. When accessing the properties or methods of any object, all properties of the object will be searched first. If not found, the properties on the prototype object will be searched step by step along the prototype chain according to [[prototype]] until found. Otherwise return undefined.

1. Prototype chain inheritance:

The prototype chain is the default way to implement inheritance in JavaScript. If you want a child object to inherit the parent object, the simplest way is to point the prototype attribute of the child object's constructor to an instance of the parent object:

Copy code The code is as follows:

function Parent() {}
function Child() {}
Child.prototype = new Parent()

At this time, Child's prototype attribute has been rewritten and points to a new object, but the constructor attribute of this new object does not correctly point to Child. The JS engine will not automatically complete this work for us, which requires us to manually The constructor property of Child's prototype object repoints to Child:
Copy code The code is as follows:

Child.prototype.constructor = Child

The above is the default inheritance mechanism in JavaScript, which migrates the properties and methods that need to be reused to the prototype object, and sets the non-reusable parts as the object's own properties. However, this inheritance method requires a new instance as the prototype object, which is efficient. It will be lower.

2. Prototypal inheritance (non-prototype chain):

In order to avoid the problem of repeatedly creating prototype object instances in the previous method, you can directly point the prototype of the child object constructor to the prototype of the parent object constructor. In this way, all properties and methods in Parent.prototype can also be reused. At the same time, there is no need to repeatedly create prototype object instances:

Copy code The code is as follows:

Child.prototype = Parent.prototype
Child.prototype.constructor = Child

But we know that in JavaScript, objects exist as reference types. This method actually points the pointers saved in Child.prototype and Parent.prototype to the same object. Therefore, when we want to use the child object prototype If you extend some properties in order to continue inheritance later, the prototype of the parent object will also be rewritten, because there is always only one instance of the prototype object here, which is also the shortcoming of this inheritance method.

3. Temporary constructor inheritance:

In order to solve the above problem, you can use a temporary constructor to act as an intermediate layer. All operations on the child object prototype are completed on the instance of the temporary constructor and will not affect the parent object prototype:

Copy code The code is as follows:

var F = function() {}
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child

At the same time, in order to access the attributes in the parent class prototype in the child object, you can add an attribute pointing to the parent object prototype in the child object constructor, such as uber. In this way, the child object can be accessed directly through child.constructor.uber. to the parent prototype object.

We can encapsulate the above work into a function, and calling this function in the future can easily implement this inheritance method:

Copy code The code is as follows:

function extend(Child, Parent) {
var F = function() {}
F.prototype = Parent.prototype
Child.prototype = new F()
Child.prototype.constructor = Child
Child.uber = Parent.prototype
}

Then you can call it like this:
Copy code The code is as follows:

extend(Dog, Animal)

4. Attribute copy:

This inheritance method basically does not change the relationship of the prototype chain, but directly copies all the attributes in the parent prototype object to the child object prototype. Of course, the copy here only applies to basic data types, and object types only support Pass by reference.

Copy code The code is as follows:

function extend2(Child, Parent) {
var p = Parent.prototype
var c = Child.prototype
for (var i in p) {
         c[i] = p[i]
}
c.uber = p
}

This method reconstructs some prototype attributes, which will be less efficient when building objects, but can reduce the search of the prototype chain. However, I personally feel that the advantages of this method are not obvious.

5. Inheritance between objects:

In addition to the inheritance method between constructors, you can also directly inherit between objects without constructors. That is, copy object attributes directly, including shallow copy and deep copy.

Shallow copy:
Accept the object to be inherited, create a new empty object at the same time, copy the properties of the object to be inherited to the new object and return the new object:

Copy code The code is as follows:

function extendCopy(p) {
var c = {}
for (var i in p) {
         c[i] = p[i]
}
c.uber = p
Return c
}

After the copy is completed, the attributes that need to be rewritten in the new object can be manually rewritten.

Deep copy:
The problem of shallow copy is also obvious. It cannot copy the attributes of the object type but can only pass the reference. To solve this problem, deep copy must be used. The focus of deep copy lies in the recursive call of copy. When the properties of the object type are detected, the corresponding object or array is created and the basic type values ​​are copied one by one.

Copy code The code is as follows:

function deepCopy(p, c) {
c = c || {}
for (var i in p) {
If (p.hasOwnProperty(i)) {
If (typeof p[i] === 'object') {
                                   c[i] = Array.isArray(p[i]) ? [] : {}
                 deepCopy(p[i], c[i])
              } else {
c[i] = p[i]
            }
}
}
Return c
}

An ES5 Array.isArray() method is used to determine whether the parameter is an array. Environments that do not implement this method need to manually encapsulate a shim.
Copy code The code is as follows:

Array.isArray = function(p) {
Return p instanceof Array
}

However, array variables from different frameworks cannot be judged using the instanceof operator, but this situation is relatively rare.

6. Prototypal inheritance:

With the help of the parent object, create a new object prototyped by the parent object through the constructor:

Copy code The code is as follows:

function object(o) {
var n
Function F() {}
F.prototype = o
n = new F()
n.uber = o
Return n
}

Here, the parent object is directly set as the prototype of the child object. The Object.create() method in ES5 is this implementation.

7. Mixed use of prototypal inheritance and attribute copying:

In the prototypal inheritance method, the child object is constructed based on the passed in parent object. At the same time, in addition to the properties provided by the parent object, additional objects that need to be copied can be passed in:

Copy code The code is as follows:

function objectPlus(o, stuff) {
var n
Function F() {}
F.prototype = o
n = new F()
n.uber = o

for (var i in stuff) {
n[i] = stuff[i]
}
Return n
}


8. Multiple inheritance:

This method does not involve the operation of the prototype chain. Multiple objects whose attributes need to be copied are passed in, and all attributes are copied in sequence:

Copy code The code is as follows:

function multi() {
var n = {}, stuff, i = 0,
        len = arguments.length
for (i = 0; i < len; i ) {
        stuff = arguments[i]
for (var key in stuff) {
n[i] = stuff[i]
}
}
Return n
}

The objects are copied in order according to the order in which they are passed in. That is to say, if the object passed in later contains the same properties as the previous object, the latter will overwrite the former.

9. Constructor borrowing:

The call() and apply() methods in JavaScript are very easy to use, and their function of changing the method execution context can also play a role in the implementation of inheritance. The so-called constructor borrowing refers to borrowing the constructor of the parent object in the child object constructor to operate this:

Copy code The code is as follows:

function Parent() {}
Parent.prototype.name = 'parent'

function Child() {
Parent.apply(this, arguments)
}
var child = new Child()
console.log(child.name)


The biggest advantage of this method is that in the constructor of the sub-object, the sub-object's own properties are completely reconstructed, and the reference type variable will also generate a new value instead of a reference, so any operation on the sub-object Neither will affect the parent object.

The disadvantage of this method is that the new operator is not used during the construction process of the child object, so the child object will not inherit any attributes on the parent prototype object. In the above code, the name attribute of the child will be undefined.

To solve this problem, you can manually set the child object constructor prototype to an instance of the parent object again:

Copy code The code is as follows:

Child.prototype = new Parent()

But this will bring about another problem, that is, the constructor of the parent object will be called twice, once during the borrowing process of the parent object's constructor, and the other time during the inheritance prototype process.

To solve this problem, we need to remove a call to the parent object's constructor. Constructor borrowing cannot be omitted, so the last call can only be removed. Another way to implement prototype inheritance is to iteratively copy:

Copy code The code is as follows:

extend2(Child, Parent)

Just use the extend2() method implemented previously.
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn