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:
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:
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:
We can encapsulate the above work into a function, and calling this function in the future can easily implement this inheritance method:
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.
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:
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.
6. Prototypal inheritance:
With the help of the parent object, create a new object prototyped by the parent object through the constructor:
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:
for (var i in stuff) {
n[i] = stuff[i]
}
Return n
}
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:
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:
function Child() {
Parent.apply(this, arguments)
}
var child = new Child()
console.log(child.name)
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:
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: