Topsy-oop[3]--JavaScript to thoroughly understand inheritance and prototype chains

Source: Internet
Author: User
Tags hasownproperty

Overview

First, let's briefly describe the concept of inheritance: When a class and another class form the "is a kind of" relationship, these two classes form an inheritance relationship. The two sides of an inheritance relationship are subclasses and base classes, and subclasses can reuse properties and methods in the base class.

In the previous article we introduced the use of constructors and prototypes to implement "classes" in JavaScript, because constructors and prototypes are objects, so JavaScript's "classes" are essentially objects. In this article we will introduce an important conceptual prototype chain in JavaScript and how to implement inheritance in JavaScript through the prototype chain.

Inheritance of C #

C # can explicitly define class, or you can have a class directly inherit from another class, and the following code is a simple inheritance.

public class person{Public    string Name {get {return ' Keepfool ';}}    public string SayHello ()    {        return ' Hello, I am ' + this. Name;}    } public class employee:person{}
We defined the name attribute and the SayHello () method in the person class, and nothing in the employee class was defined.
Because the employee class inherits the person class, an instance of the employee class can use the properties and methods of the person class.
Employee EMP = new Employee (); Console.WriteLine (EMP. Name); Console.WriteLine (EMP. SayHello ()); Console.WriteLine ("Emp{0} is an instance of the person class", EMP is a person? "": "No");

After you create an EMP object using the constructor of the employee class, the EMP object can use the Name property and the SayHello () method.
The EMP object is both an instance of the employee class and an instance of the person class.

This is the inheritance syntax for C #, and JavaScript does not provide this syntax, so let's explore how to implement inheritance in JavaScript.

JavaScript prototype inheritance

Similarly, we first define two classes of person and employee in JavaScript.

function person () {this.name = ' keefool '; This.sayhello = function () {return ' Hello ', I am ' + this.name;}} function Employee (email) {this.email = email;} var person = new Person (), var emp = new Employee (' [email protected] ');

Since employee and person are not an inheritance relationship, EMP is currently an instance of the employee class, not an instance of the person class, so it cannot access the Name property of the person class and the SayHello () method.

The instanceof operator can also be used to determine that an EMP is an instance of the employee class, not an instance of the person class.

Implementing inheritance

Let us ask ourselves, what is the purpose of achieving inheritance? Of course, subclasses reuse the properties and methods of the base class.
In this example, it is quite true that an instance of the employee class can use the Name property of the person class and the SayHello () method.

So how does JavaScript implement inheritance?
There are many kinds of answers, and here I'll just introduce a more common one--to inherit through the prototype.

Recalling the previous article, we know that the person () constructor has a prototype property, which is an object.
The properties and methods defined in Person.prototype can be used by instances of person.

That being the case, we can of course define some properties and methods on the Employee.prototype.
See here, do you know how to do it? Direct Employee.prototype Point to an instance of the person class.

function person () {this.name = ' keefool '; This.sayhello = function () {return ' Hello ', I am ' + this.name;}} function Employee (email) {this.email = email;} var person = new person (); Employee.prototype = Person;var emp = new Employee (' [email protected] ');

Now we have access to the Emp.name and Emp.sayhello () methods.

In the chrome console, using the instanceof operator, you can see that the EMP object is now an instance of the person class.

How is this implemented?

Because Employee.prototype is a reference type, it points to an instance of person in the person class, and the person holds the Name property and the SayHello () method.
This allows us to use employee.prototype just as with instances of person, accessing the Emp.name and Emp.sayhello () methods actually accesses the Person.name and Person.sayhello () methods.

If you have doubts about this code, you can also understand that:

var person = new person (); Employee.prototype.name = Person.name; Employee.prototype.sayHello = Person.sayhello;

Of course, these two lines of code can be combined into one line because the person object is not used at all.

function person () {this.name = ' keefool '; This.sayhello = function () {return ' Hello ', I am ' + this.name;}} function Employee (email) {this.email = email;} Employee.prototype = new Person (), var emp = new Employee ('[email protected]');

The following diagram summarizes this process:

Note that the name and SayHello () methods are not the own properties and methods of the employee class, it originates from Employee.prototype.

The nature of prototype inheritance

The prototype inheritance of JavaScript is Object-based, that is, the prototype object of one class points to an instance of another class.

In combination with the above description, since Employee.prototype points to an instance of the person class, we can say that the employee class inherits the person class.

Also, even if we don't explicitly set employee.prototype,javascript, we'll do one thing by default:

Employee.prototype = {};

{}Represents an instance of an ordinary object class, which means that employee is also an instance of the object class.

Besides, the constructor property of the constructor object

As mentioned earlier, each object has a constructor property, and the constructor property should point to the object's constructor, such as the constructor attribute of the person instance to the person () constructor.

var person = new person ();

When Employee.prototype is not set, the EMP object's constructor is originally directed to the employee () constructor.

When set Employee.prototype = new Person(); , the EMP object's constructor points to the person () constructor.

Invisible, Emp.constructor was rewritten.
The EMP object does not look like it was created by the employee () constructor, but rather by the person () constructor.
Do you have this kind of confusion?

This is not what we expected, and we want the EMP object to appear to be created by the employee () constructor, which means that emp.constructor should be directed to the employee () constructor.
To solve this problem, we first figure out where the constructor property of the object came from, and where it came from, we know why Emp.constructor was rewritten.

The source of the constructor property

The constructor property is the own property of the constructor prototype object when we do not have a prototype object that overrides the constructor.
For example: The prototype of the person () constructor is not rewritten, and constructor is the Person.prototype property.

When we rewrite the constructor, the constructor property is not the intrinsic property of the constructor prototype object.
For example: After the prototype of the Employee () constructor has been rewritten, constructor is not Person.prototype's own property.

The constructor property of Employee.prototype is the one that points to the person () constructor.

This means that when an object is created, the object itself does not have a constructor property, but rather a prototype object from the constructor that created the object.

That is, when we access emp.constructor, the actual access is employee.prototype.constructor,employee.prototype.constructor actually refers to the person () constructor, The Person.constructor reference is the person () constructor, and the person () constructor is actually Person.prototype.constructor.

This relationship is a bit messy, we can use the following expressions to express this relationship:

Emp.constructor = Person.constructor = Employee.prototype.constructor = person = Person.prototype.constructor

They all end up pointing to person.prototype.constructor!.

Rewriting the constructor of a prototype object

The problem is solved by figuring out the constructor properties of the object to get the pulse.
The solution is to have Employee.prototype.constructor point to the Employee () constructor.

function person () {this.name = ' keefool '; This.sayhello = function () {return ' Hello ', I am ' + this.name;}} function Employee (email) {this.email = email;} Employee.prototype = new Person (); Employee.prototype.constructor = Employee;var emp = new Employee ('[email protected]');

If you still don't understand the key line of code:

Employee.prototype.constructor = Employee;

You can try to understand from the perspective of C # that an instance of the Employee class in C # is definitely created by the constructor of the employee class.

Prototype Chain __PROTO__ Properties

We already know that when defining a function, the function has the prototype property, which points to an object.
The object that the prototype property points to is shared, which is somewhat like a static property in C #.
From the perspective of C #, the instance is not able to access the static properties of the class.
So in JavaScript, why do objects have access to properties and methods in prototype?

When an object is created by the new constructor, the object comes with a __proto__ property, which is assigned by JavaScript.
This attribute points to the prototype of the constructor.

For example, when an EMP object is created, JavaScript automatically assigns an __proto__ property to the EMP object, which is pointing to Employee.prototype.

See what's included in Chrome emp.__proto__

First, it ▼Person {name: "keepfool"} means that emp.__proto__ is a person object because Employee.prototype does point to a person object.
Secondly, we divide the attributes of emp.__proto__ into 3 parts.

1. Part 1th: The name attribute and the SayHello () method, two of which originate from the Person object. We call this part an inherited property and method.

2. Part 2nd: Constructor property, because we have overridden the constructor property of the employee () constructor's prototype object, that Employee.prototype.constructor = Employee is, so constructor is pointing to the employee () constructor.

3. Part 3rd: __proto__ It points to a Object,person class that is the parent class of the employee class, so who is the parent of the person class? --object class.

The __proto__ property of an object is like a secret link that points to the prototype object of the constructor.

What is a prototype chain

We notice that part 3rd is still a __proto__ attribute, and we unfold it to see what it is.

Look down again, there are two layers of __proto__.

EMP.__PROTO__.__PROTO__: ?constructor:function Person() It can be seen as a prototype of the person () constructor.

This also illustrates that when the person () constructor is created, JavaScript automatically assigns the prototype property to the person () constructor.

Person.prototype contains two parts: the person () constructor, and a __proto__ property that points to the built-in object object, which is the emp__proto__.__proto__.__proto__ The object is pointed to.

We refer to this series as the __proto__ prototype chain.

The prototype chain also represents the inheritance of JavaScript, the employee class inherits the person class, and the person class inherits the object class.

In combination with these two graphs, it is not difficult to see that the bottom of the prototype chain is NULL, because the bottom object object has no __proto__ property.

Understanding the prototype chain

This explains why the EMP object has access to the Employee.prototype's Name property and the SayHello () method.
To access the SayHello () method, for example, we use a few slow shots to illustrate:

    1. Access the SayHello () method via the EMP object, i.e. Emp.sayhello ()
    2. The JavaScript engine discovers that the SayHello () method is not the own property of the EMP object, that is, the SayHello () method is not defined in the Employee class.
    3. So the JavaScript engine went to the EMP's upper-level prototype chain, emp.__proto__
    4. Because emp.__proto__ and Employee.prototype hold the same references, they all point to a person object
    5. So JavaScript went to the person object to find the SayHello () method, which was found by JavaScript, and used this method.

With these footage in mind, note what JavaScript has done for us in the back of the 3 steps of executing ①③④ in our code.

It is worth noting that the above access to the SayHello () method, the actual access isemp.__proto__.sayHello()

To promote a method to a prototype object

As mentioned in the previous article, the SayHello () method of the person class is more appropriate in its prototype object so that all the person instances share a copy of the Sayhelo () method, and what happens if we refer to this method as a prototype object?

function person () {this.name = ' keefool ';} Person.prototype.sayHello = function () {return ' Hello, I am ' + this.name;} function Employee (email) {this.email = email;} Employee.prototype = new Person (); Employee.prototype.constructor = Employee;var emp = new Employee ('[email protected]');

You can see that the path to the SayHello () method is: emp.__proto__.__proto__.sayHello() more than the direct definition in the person () constructor.

In this way, it seems that the definition of the method in the prototype object is not absolutely good, it will make JavaScript traverse more layers of the prototype chain, there will be some performance loss.

Prototype Chain Example

To strengthen the understanding of the prototype chain, let's make a simple example.

From the above illustration, we can know that the ToString () method is an object, and we use the ToString () method to illustrate the example.

In the chrome console input emp.tostring (), we get the result "[object Object]" .
Through the prototype chain and the hasOwnProperty () method, it can be seen that the ToString () method is found through a 3-layer prototype chain, or emp.__proto__.__proto__.__proto__, which shows that it is an object.

The emp.tostring () output "[object Object]" is meaningless, and now we define a toString () method on the prototype of the person () constructor.

function person () {this.name = ' keefool ';} Person.prototype.sayHello = function () {return ' Hello, I am ' + this.name;} Person.prototype.toString = function () {return ' [' + THIS.name + '] ';} function Employee (email) {this.email = email;} Employee.prototype = new Person (); Employee.prototype.constructor = Employee;var emp = new Employee ('[email protected]');

Through the prototype chain and the hasOwnProperty () method, it can be seen that the ToString () method is found through a 2-layer prototype chain, or emp.__proto__.__proto__.
EMP.__PROTO__.__PROTO__ is the prototype object of the person () constructor, which is Person.prototype.

This example is also a simple rewrite example, although object provides the ToString () method, but its subclass person overrides the ToString () method, and the EMP eventually calls the ToString () method of the person.

Topsy-oop[3]--JavaScript to thoroughly understand inheritance and prototype chains

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.