JavaScript prototype inheritance detailed _javascript skills

Source: Internet
Author: User

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

JavaScript inheritance is not the same as C + + inheritance, and C + + inheritance is class based, and JavaScript inheritance is based on prototypes.

Now the question is coming.

What's the prototype? We can refer to the classes in C + +, and also save the object's properties and methods. For example, we write a simple object

Copy Code code as follows:

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, which has a property name and a method SetName. Note that once you modify prototype, such as adding a method, all instances of that object will enjoy this method. For example

Copy Code code as follows:

function Animal (name) {
THIS.name = name;
}
var animal = new Animal ("Wangwang");

At this point animal only the name attribute. If we add a sentence,

Copy Code code as follows:

Animal.prototype.setName = function (name) {
THIS.name = name;
}

At this time animal will also have SetName method.

Inherit this copy--from the empty object we know that the basic type of JS is called object, and its most basic instance is the empty object, that is, directly call the instance generated by the new object (), or it is declared with a literal amount of {}. Empty objects are "clean objects," only predefined properties and methods, and all other objects are inherited 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 instance created by the constructor must be copied from a. Because an instance is copied from object A, the instance must inherit all of the properties, methods, and other properties of a. So how does replication happen? Method One: Construct a copy every instance of the construct, and copy an instance from the prototype, and the new instance takes up the same memory space as the prototype. While this makes obj1, Obj2 and their prototypes "completely consistent", but also very economical--memory space consumption will increase rapidly. As shown in figure:


Method Two: Write-time replication This strategy comes from the technology of a consistent spoofing system: write-time replication. A typical example of this deception is the dynamic-link library (DDL) in the operating system, where the memory area is always copied when it is written. As shown in figure:


We simply specify that obj1 and Obj2 are equivalent to their prototypes in the system, so that when reading, we just need to follow the instructions to read the prototype. When you need to write the properties of an object (such as Obj2), we copy the image of a prototype and then point the operation to that image. As shown in figure:


The advantage of this approach is that we don't need a lot of memory overhead when we create instances and read properties, we use some code to allocate memory for the first time, and some code and memory overhead. Since then, there is no such overhead, because the efficiency of the access image and the access prototype is consistent. However, for systems that write frequently, this approach is no more economical than the previous approach. Method Three: Read traversal This method changes the granularity of replication from prototype to member. This approach is characterized by copying the members ' information to the instance image only if the members of an instance are written. When writing object properties, such as (obj2.value=10), a property value named value is generated and placed in the member list of the Obj2 object. Look at the picture:

As you can see, Obj2 is still a reference to the prototype, and there are no instances of objects of the same size that were created during the operation. In this way, the write operation does not cause a large amount of memory allocation, so the memory is used on the economy. The difference is that obj2 (and all object instances) need to maintain a list of members. This list of members follows two rules: guaranteed to be accessed first when reading, if no attributes are specified in the object, attempt to traverse the entire prototype chain of the object until the prototype is empty or the attribute is found. The prototype chain will speak later. Obviously, read traversal is the best performance in three ways. So, the prototype inheritance of JavaScript is read traversal. Constructor familiar with C + + people read the code of the top object, will certainly be puzzled. No class keyword is ok to understand, after all, there are function keywords, the keyword is not the same. But what about the constructor? In fact, JavaScript also has a similar constructor, just called a constructor. When you use the new operator, you have actually called the constructor and bound this to an object. For example, we use the following code

Copy Code code as follows:

var animal = animal ("Wangwang");

Animal will be undefined. Some would say that no return value is of course undefined. So if you change the Animal object definition:

Copy Code code as follows:

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 extended so that window has the name attribute. This is because this is the default point to window, or topmost variable, without specifying it. The constructor can be called correctly only if the new keyword is invoked. So, how to avoid the use of the person missing the new keyword it? We can make some minor changes:

Copy Code code as follows:

function Animal (name) {
if (!) ( This instanceof Animal)) {
return new Animal (name);
}
THIS.name = name;
}

That would be a foolproof thing. The constructor also has a useful indication of which object the instance belongs to. We can use instanceof to judge, but the instanceof returns true to the Ancestor object and the true object when inheriting, so it is not appropriate. constructor when new calls, the default point is to the current object.

Copy Code code as follows:

Console.log (Animal.prototype.constructor = = = Animal); True

We can think of another way: prototype at the beginning of the function is not a value, the implementation may be the following logic

The set __PROTO__ is a member of the function built-in, Get_prototyoe () is its method

Copy Code code as follows:

var __proto__ = null;
function Get_prototype () {
if (!__proto__) {
__proto__ = new Object ();
__proto__.constructor = this;
}
return __proto__;
}

The benefit is to avoid the overhead of creating an object instance per function declaration. Constructor can be modified, which will be mentioned later. Based on the prototype inheritance is what I believe everyone is almost know, do not show the lower IQ.

JS's inheritance There are several, here speak two kinds of

1. Method One of the most common methods, security is also better. Let's define two objects first.

Copy Code code as follows:

function Animal (name) {
THIS.name = name;
}
function Dog (age) {
This.age = age;
}
var dog = new Dog (2);

To construct inheritance is simple, point the child object's prototype to an instance of the parent object (Note is an instance, not an object)

Copy Code code as follows:

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

Copy Code code as follows:

Console.log (dog instanceof Animal); True
Console.log (dog instanceof dog); False

That's the inheritance, but there's a little problem.

Copy Code code as follows:

Console.log (Dog.prototype.constructor = = = Animal); True
Console.log (Dog.prototype.constructor = = = Dog); False

You can see that the object that the constructor points to changes, so it doesn't fit our purpose, and we can't tell who our new instance belongs to. So, we can add one sentence:

Copy Code code as follows:

Dog.prototype.constructor = Dog;

Look again:

Copy Code code as follows:

Console.log (dog instanceof Animal); False
Console.log (dog instanceof dog); True

Done This method is part of the maintenance of the prototype chain, which is described in detail below. 2. Method II This method has its advantages, but also its drawbacks, but more harm than good. Look at the code first

Copy Code code as follows:

<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 the prototype to be copied.

The advantage of this approach is that there is no need to instantiate objects (compared to method one), saving resources. The disadvantage is obvious, in addition to the same problem as above, that is, constructor point to the parent object, you can only copy the parent object with prototype declared properties and methods. That is to say, in the code above, the Name property of the animal object is not replicated, but the SetName method can be copied. Most fatally, any modification of the prototype of the child object affects the prototype of the parent object, which is how the two-object-declared instance will be affected. Therefore, this method is not recommended.

Prototype chain

People who have written inheritance know that inheritance can be inherited from multiple layers. And in JS, this constitutes the prototype chain. The prototype chain has been mentioned several times, so what is the prototype chain? An instance should at least have the Proto attribute 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 it from the "constructor prototype chain" (which we usually call "prototype chain"), which is composed of the constructor's prototype. Let's construct a simple inheritance relationship by following the above code:

Copy Code code as follows:

function Animal (name) {
THIS.name = name;
}
function Dog (age) {
This.age = age;
}
var animal = new Animal ("Wangwang");
Dog.prototype = animal;
var dog = new Dog (2);

To remind you that all objects are inherited empty objects, as previously stated. So, we construct a prototype chain:


We can see that the prototype of the child object points to an 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, forming an internal prototype chain. When we need to look for a property, the code is similar to the

Copy Code code as follows:

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 up the Name property in dog, it will look in the list of members in dog, which, of course, will not be found, because the list of dog members now has only age. Then it will follow the prototype chain, that is, the. Proto point to the instance to continue looking for, that is, the animal, found the Name property and returned it. If you are looking for a nonexistent attribute, it will continue to follow when you are not looking for it in the animal. Proto looking for, found the empty object, cannot find it and then continues to follow. Proto to find, while the empty object's. Proto points to null, looking for exit.

The maintenance of the prototype chain we raised a problem when we spoke about prototype inheritance, when you use method one to construct inheritance, the constructor of child object instances point to the parent object. The advantage is that we can access the prototype chain through the constructor attribute, and the downside is obvious. An object, it produces an instance that should point to itself, and that is

Copy Code code as follows:

(New obj ()). Prototype.constructor = = obj;

Then, when we rewrite the stereotype properties, the constructor of the instance that the child objects produce is not pointing to itself! This is contrary to the original intention of the constructor. One of the solutions we mentioned above is:

Copy Code code as follows:

Dog.prototype = new Animal ("Wangwang");
Dog.prototype.constructor = Dog;

There seems to be nothing wrong with it. But in fact, this poses a new problem because we will find that we cannot backtrack the prototype chain because we cannot find the parent object, and the. Proto property of the internal prototype chain is inaccessible. Thus, SpiderMonkey provides an improved solution: A property named __proto__ is added to any created object that always points to the stereotype used by the constructor. In this way, any constructor modification, will not affect the value of __proto__, it is convenient to maintain the constructor.

But there are two questions:

__proto__ can be rewritten, which means there is still a risk when using it

__PROTO__ is a special treatment for SpiderMonkey that is not available in other engines, such as JScript.

We also have a way of maintaining the constructor property of the stereotype and initializing the constructor property of the instance within the subclass constructor function.

The code is as follows: Overwrite child objects

Copy Code code as follows:

function Dog (age) {
This.constructor = Arguments.callee;
This.age = age;
}
Dog.prototype = new Animal ("Wangwang");

In this way, the constructor of all instances of all child objects point to the object correctly, while the constructor of the prototype points to the parent object. Although this method is inefficient, because each instance of the construction is overridden by the constructor attribute, there is no doubt that this approach can effectively resolve the previous contradictions. ES5 takes this into account and solves the problem thoroughly: 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, as the previous section looks for object attributes, we can rewrite the following:

Copy Code code as follows:

function Getattrfromobj (attr, obj) {
if (typeof (obj) = = "Object") {
do {
var proto = Object.getprototypeof (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 approach. The more appropriate approach is to integrate the two methods, which is believed that readers are very good at, here is not shortcoming.

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.