Prototype inheritance for JavaScript

Source: Internet
Author: User

JavaScript is an object-oriented language. In JavaScript there is a classic word that all things are objects. Since it is object-oriented, there are three main features of object-oriented: encapsulation, inheritance, polymorphism. This is about the inheritance of JavaScript, the other two can be said later.

The inheritance of JavaScript is not the same as C + +, the inheritance of C + + is class-based, and JavaScript inheritance is based on prototype.

Now that's the problem.

What is a prototype? Prototypes we can refer to the classes in C + + and save the properties and methods of the object as well. For example, we write a simple object
function Animal (name) {    this.name = name;} Animal.prototype.setName = function (name) {    this.name = name;} var animal = new Animal ("Wangwang");


As we can see, this is an object animal, the object has a property name, there is a method setname. Note that once you modify prototype, such as adding a method, all instances of that object will share this method. For example
function Animal (name) {    this.name = name;} var animal = new Animal ("Wangwang");

At this point animal only the Name property. If we add a sentence,
Animal.prototype.setName = function (name) {    this.name = name;}
At this time animal also will have SetName method.

Inherit this copy--from an empty object we know that the basic type of JS is called object, and its most basic instance is an empty object, that is, invoking the instance generated by the new object directly, or declaring it with the literal {}. Empty objects are "clean objects", only predefined properties and methods, and all other objects inherit from empty objects, so all objects have these predefined properties and methods. A prototype is actually an object instance. The meaning of a prototype is that if the constructor has a prototype object A, the instances created by the constructor are necessarily copied from a. Because the instance is copied from object A, the instance inevitably inherits all of the properties, methods, and other properties of a. So, how is replication implemented? Method One: Construct a copy of each instance of the construct, copy an instance from the prototype, and the new instance and prototype occupy the same memory space. This makes the obj1, Obj2 and their prototypes "exactly", but also very non-economical-the memory space consumption will increase rapidly.
Method Two: Copy-on-write this strategy comes from the technology of a consistent spoofing system: copy-on-write. A typical example of this deception is the dynamic link library (DDL) in the operating system whose memory area is always copied when it is written.
We just need to indicate in the system that OBJ1 and obj2 are equivalent to their prototypes, so that when reading, just follow the instructions to read the prototype. When you need to write the properties of an object (for example, obj2), we copy the image of a prototype and point it to that image.
The advantage of this approach is that we do not need a lot of memory overhead when creating instances and read properties, and we use some code to allocate memory for the first write, and to bring some code and memory overhead. However, this overhead is no longer available since the efficiency of accessing the image and accessing the prototype is consistent. However, this approach is no more economical than the last method for a system that writes frequently. Method Three: Read and traverse this method to change the granularity of replication from prototype to member. The feature of this approach is that only when a member of an instance is written, the information of the member is copied to the instance image. When writing an object property, for example (obj2.value=10), a property value named value is generated and placed in the member list of the Obj2 object. Look at the picture:
It can be found that obj2 is still a reference to the prototype and is not created with an object instance of the same size as the prototype during the operation. In this way, the write operation does not result in a large amount of memory allocation, so the use of memory appears to be economical. The difference is that obj2 (and all object instances) need to maintain a list of members. This member list follows two rules:
    1. Guaranteed to be accessed first when read
    2. If no attribute is specified in the object, an attempt is attempted to traverse the entire prototype chain of the object until the prototype is empty or the property is found.
The prototype chain will speak later. Obviously, in three methods, read traversal is the best performance. SoJavaScript's prototype inheritance is read-traversed. Constructor familiar with C + + people read the top of the object code, will certainly be puzzled. No class keyword is ok to understand, after all, there is a function keyword, the keyword is not the same. But what about the constructor? In fact, JavaScript has a similar constructor, just called a constructor. When using the new operator, the constructor is actually called and the This is bound to an object. For example, we use the following code
var animal = animal ("Wangwang");
Animal will be undefined. Some would say that there is no return value of course undefined. If you change the object definition of animal:
function Animal (name) {    this.name = name;    return this;}
Guess what animal is now?
At this point the animal becomes window, except that the window is expanded so that window has the Name property. This is because this, when not specified, points to the window, which is the top-level variable, by default. The constructor can be called correctly only if the new keyword is called. So, how to avoid the use of people missing the new keyword? We can make some minor changes:
function Animal (name) {    if (!) ( This instanceof Animal) {        return new Animal (name);     }    THIS.name = name;}
This will be foolproof. The constructor also has a use to indicate which object the instance belongs to. We can use instanceof to judge, but Instanceof will return true to both the ancestor object and the real object at the time of inheritance, so it is not suitable. constructor when new is called, it points to the current object by default.
Console.log (Animal.prototype.constructor = = = Animal); True
We can think of a different kind of thinking: prototype at the beginning of the function is no value at all, the implementation may be the following logic
Set __PROTO__ is a function built-in member, Get_prototyoe () is its method var __proto__ = Null;function Get_prototype () {    if (!__proto__) {        _ _proto__ = new Object ();        __proto__.constructor = this;    }    return __proto__;}
The benefit is to avoid creating an object instance for each declaration of a function, saving overhead. Constructor can be modified and will be discussed later. Prototype-based inheritance inheritance what is the belief that we all know about it, we don't show the lower IQ. There are several kinds of JS inheritance, here are two kinds of 1. Method One is the most commonly used method, and the security is better. Let's define two objects first.
function Animal (name) {    this.name = name;} function Dog (age) {    this.age = age;} var dog = new Dog (2);

To construct inheritance it is simple to point the prototype of a child object to an instance of the parent object (note that it is an instance, not an object)
Dog.prototype = new Animal ("Wangwang");
At this point, dog will have two attributes, name and age. And if you use the instanceof operator for dog
Console.log (dog instanceof Animal); Trueconsole.log (dog instanceof dog); False
That's the inheritance, but there's a little problem.
Console.log (Dog.prototype.constructor = = = Animal); Trueconsole.log (Dog.prototype.constructor = = = Dog); False
You can see that the object that the constructor points to has changed so that it does not fit our purpose, and we cannot judge who our new instance belongs to. Therefore, we can add a sentence:
Dog.prototype.constructor = Dog;
Look again:
Console.log (dog instanceof Animal); Falseconsole.log (dog instanceof dog); True
Done This approach is part of the maintenance of the prototype chain, which is described in detail below. 2. Method Two This method has its advantages, but also has its drawbacks, but the disadvantages outweigh the benefits. Look at the code first
<pre name= "Code" class= "JavaScript" >function Animal (name) {    this.name = name;} Animal.prototype.setName = function (name) {    this.name = name;} function Dog (age) {    this.age = age;} Dog.prototype = Animal.prototype;
This enables a copy of the prototype. The benefit of this approach is that there is no need to instantiate objects (compared to method one), saving resources. The disadvantage is also obvious, except for the same problem as above, that constructor points to the parent object and can only replicate the properties and methods declared by the parent object with prototype. That is, the name property of the animal object is not replicated in the code above, but the SetName method can be copied. Most fatally, any modification to the prototype of a child object affects the prototype of the parent object, which means that the instances declared by the two objects are affected. Therefore, this method is not recommended. The prototype chain is known to all who inherit, and inheritance can inherit multiple layers. In JS, this constitutes the prototype chain. The prototype chain is also mentioned many times earlier, so what is the prototype chain? An instance, at least, should have a proto property that points to the prototype, which is the basis of the object system in JavaScript. This attribute is not visible, however, and we call it the "internal prototype chain", which separates the "constructor prototype chain" (which we typically refer to as the "prototype Chain") composed of the prototype of the constructor. Let's start by building a simple inheritance relationship with the code above:
function Animal (name) {    this.name = name;} function Dog (age) {    this.age = age;} var animal = new Animal ("Wangwang");D Og.prototype = Animal;var dog = new Dog (2);

As a reminder, the previous article said that all objects are inherited from empty objects. So, we construct a prototype chain:


As we can see, the prototype of the child object points to the instance of the parent object, which forms the constructor prototype chain. The internal proto object of the child instance is also an instance of the parent object, which forms the internal prototype chain. When we need to look for a property, the code is similar to

function Getattrfromobj (attr, obj) {    if (typeof (obj) = = = = "Object") {        var proto = obj;        while (proto) {            if (Proto.hasownproperty (attr)) {                return proto[attr];            }            Proto = proto.__proto__;        }    }    return undefined;}

In this example, if we look for the name attribute in dog, it will look in the list of members in dog, and of course, it will not be found, because now the member list of dog is only age. It then follows the prototype chain, the. Proto-pointed instance, where the Name property is found and returned, in animal. If you are looking for a property that does not exist, it will continue to follow the. Proto Search, find the empty object, and then continue to follow the. Proto search, while the empty object's. Proto points to null, looking for an exit from the animal.

Maintenance of the prototype chain we raised a question when we were talking about prototype inheritance, and when using the method one constructs inheritance, the constructor of the child object instance points to the parent object. The advantage is that we can access the prototype chain through the constructor property, and the downside is obvious. An object that produces an instance that should point to itself, that is,
Then, when we rewrite the prototype property, the constructor of the instance produced by the child object is not pointing to itself! This is contrary to the original intention of the constructor. We mentioned a solution above:
Dog.prototype = new Animal ("Wangwang");D og.prototype.constructor = Dog;
There seems to be no problem. But in fact, this brings up a new problem, because we'll find that we can't go back to the prototype chain because we can't find the parent object, and the internal prototype chain's. Proto property is inaccessible. As a result, SpiderMonkey provides an improved solution: A property named __proto__ is added to any created object, which always points to the prototype used by the constructor. In this way, any constructor changes will not affect the value of __proto__, it is convenient to maintain the constructor. However, there are two problems:
    1. __proto__ can be overridden, which means that there is still a risk of using it
    2. __PROTO__ is a special treatment for SpiderMonkey, which is not available in other engines such as JScript.
We also have the option of maintaining the constructor property of the prototype, and initializing the constructor property of the instance within the subclass constructor function. The code is as follows: Overwrite child objects
function Dog (age) {    this.constructor = Arguments.callee;    This.age = age;} Dog.prototype = new Animal ("Wangwang");
This way, the constructor of all instances of the child object point to the object correctly, and the constructor of the prototype points to the parent object. Although this method is inefficient, because each instance of the construct overrides the constructor attribute, there is no doubt that this method can effectively resolve the previous contradiction. ES5 this situation, the problem is solved completely: you can use Object.getprototypeof () at any time to get a real prototype of an object without having to access the constructor or maintain an external prototype chain. So, looking at the object properties as described in the previous section, we can rewrite the following:
function Getattrfromobj (attr, obj) {if (typeof (obj) = = = = "Object") {do {var proto = Object.getprotot            Ypeof (dog);            if (Proto[attr]) {return proto[attr];    }} while (proto); } return undefined;}
Of course, this method can only be used in browsers that support ES5. For backwards compatibility, we still need to consider the previous method. A more appropriate approach is to integrate the two approaches into a package, which is believed to be very good for the reader and is not caught dead.


Prototype inheritance for JavaScript

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.