How JavaScript prototype works (and how to use it to implement class inheritance)

Source: Internet
Author: User

Original article: How JavaScript Prototype Really Works


This is the second article in The JavaScript technology series. I plan to discuss in depth the most confusing JavaScript prototype object and how to use it to implement inheritance.


In the previous article, we analyzed in detail the constructor and how to turn it into a class in object-oriented language. However, JavaScript is not a class-based programming language. It is a prototype-based programming language. What does this mean? Simply put, JavaScript does not create objects through classes, but through objects.




JavaScript: prototype-based language)


In a traditional class-based object-oriented language (such as Java or C ++), before creating an object, you must first create a class to define the attributes and methods of this object. So this class becomes the blueprint for creating objects, just like building a house based on the actual blueprint in reality.


After you define the class, you can use it to create an object immediately. We use the new keyword to create a corresponding object based on the class. For this process, we have a wonderful name: Class instantiation. The newly created object will have all the attributes and methods defined by the class. In the traditional class-based language, we can do this:

public class Shape {private int height;private int width;public Shape(int h, int w) {height = h;width = w;}public int area() {return height * width;}}Shape shape = new Shape(10, 2);System.out.println(shape.area());  // 20


JavaScript has no classes, and some are only objects and basic data types. To simplify the problem, let's just say that everything in JavaScript is an object, from a real number to a string, or even a function itself. As mentioned in the previous article, there are two ways to create an object: one is to create an object literally (in some cases, it is called creating an object using a JSON symbol ), another method is through constructor. Because of the purpose of this article, we will only consider the latter in the future.


Before creating an object, you must create a function (that is, a constructor ). When the new keyword is used to create an object, this function is used as a blueprint. The newly created object copies all attributes and methods defined in the function body. This is how the prototype language uses objects to create objects (Note: A function is a function-type object ):

function Shape() {this.height = 10;this.width = 10;this.area = function() {return this.height * this.width;};};var shape = new Shape();console.log(shape.area());  // 100


However, many attributes and methods are not defined in the corresponding constructor, but the objects created with them can still be accessed. For example, the toString () method. Any object can use this method to output a string about itself. The Shape () function does not define this method, but the shape object can still use it.
console.log(shape.toString());  // "[object Object]";


So where does the object obtain these methods? The answer is from the JavaScript prototype.




JavaScript prototype



Every JavaScript Object has a property that is usually hidden, called [Prototype]. [[Prototype] the attribute value is actually a pointer pointing to an object. When JavaScript cannot find an attribute on the current object, it will delegate (delegation) to this object (the Translator's note: [Prototype] points to something ). Delegation means that when you cannot do one thing, you ask others to do it for you.


When you want to access an attribute on an object, JavaScript first checks whether the object has this attribute. If not, JavaScript will look for its [[Prototype] value to see if the requested property exists on the object to which the value points. This operation continues until this attribute is found or the [[Prototype] returns null. This is the so-called prototype chain, linking objects, and every object is a node in this chain. In most browsers, the [[Prototype] attribute of an object can be accessed through a non-standard method, that is, an attribute named _ proto, another method is generally feasible, that is, Object. isPrototypeOf () method.


Now return to the example of shape. toString () mentioned above. When we call the toString () method on the shape object, JavaScript first looks for this method on the shape object, but finds that it does not. So JavaScript began to look for another object pointed to by the [[Prototype] value of the shape. There is no toString () method on this object. Then we continue to find another new object that the [[Prototype] value of this object points. Finally, JavaScript finally finds the toString () method, so JavaScript uses this method and terminates the prototype chain search process.





Now we use the hasOwnProperty () method to verify the above inference. Every object has this method. If an object has an attribute, hasOwnProperty () returns true; otherwise, false.
<喎?http: www.bkjia.com kf ware vc " target="_blank" class="keylink"> VcD4KPHByZSBjbGFzcz0 = "brush: java;"> console. log (shape. hasOwnProperty ('tostring'); // falseconsole. log (shape. _ proto __. hasOwnProperty ('tostring'); // falseconsole. log (shape. _ proto __. _ proto __. hasOwnProperty ('tostring'); // true


So, since we have not done anything, how is this prototype chain built? How is a shape object added to it? It seems that JavaScript will automatically add all created objects to a prototype chain. But what exactly does it do? In fact, the function. prototype attribute above the Shape function is used.




Function. prototype attribute of the function


Each function has a public attribute called function. prototype. It is not the same as the [[Prototype] attribute of each object, but it is not completely irrelevant. Function. prototype is actually a pointer that points to an object. When you use the new keyword to create an instance using a function (in fact, an instance is actually an object, however, this article uses the term "object" too much. In order to avoid misunderstanding in language as much as possible, I would like to call an instance created by the constructor ".) JavaScript will function the function. the prototype value is assigned to the [[Prototype] attribute of the newly created instance. In this way, the [[Prototype] attribute of the instance and the function of the function. the prototype attribute points to the same object. Through function. prototype, JavaScript can know how to add newly created objects to the prototype chain. The function. prototype attribute of the function can be
The "prototype" keyword is used for direct access.


So how is the function. prototype attribute set for a function? We don't need to implement this step by ourselves. JavaScript will do it for us. When you create a function, JavaScript creates a new object for it to implement its function. prototype attribute. This new object does not have any attributes or methods. Of course, except for the [Prototype] attribute, it is only used as a link in the Prototype chain, link different things together. Due to the lack of a proper term, I would like to call this object a "null object of a function ". After an "Empty object" is created, JavaScript points the function's function. prototype attribute to it. Therefore, it prepares the information required to establish the prototype chain in the future.


Return to the previous Shape example. When creating the Shape function, JavaScript creates an "Empty object" for it, and then returns the function of the Shape function. the prototype property points to this "null object ". When you use the new keyword to create a new instance using the Shape function, JavaScript will look for the function of the Shape function. prototype attribute (pointing to "null object"), and then pointing the [[Prototype] attribute of the new instance to this "null object ".





We can use the comparison operator to verify whether the [[Prototype] attribute of the shape instance and the function. prototype attribute of the Shape function point to the same thing. We can use a strict comparison operator to return true only when two objects are the same:

function Shape() {this.height = 10;this.width = 10;this.area = function() {return this.height * this.width;};};console.log(Shape.prototype);  // Shape {}var shape = new Shape(); console.log(shape.__proto__); // Shape {} console.log(shape.__proto__ === Shape.prototype); // true 


You can manually change the function. prototype attribute of the function so that it points to another object according to your meaning, so that you can control how to build a prototype chain. This is the principle of implementing class inheritance in JavaScript.




Prototype inheritance of JavaScript


The prototype chain of JavaScript is the key to inheritance. The inheritance of JavaScript is not like that of a class-based language. In a class-based language, all attributes and Methods declared by sub-classes and parent classes are stored on the objects created by a sub-class.


In a prototype language, there is no subclass object or parent class object. In fact, an object will only save the attributes and Methods declared in the function used to create it. As for the attributes and methods of the parent class, it will be dynamically obtained through the prototype chain. This is the so-called prototype inheritance.


To implement inheritance, we need to first create two functions, one for inheriting the other:

function Shape() {this.height = 10;this.width = 10;this.area = function() {return this.height * this.width;};};// The Triangle function will inherit from the Shape function function Triangle() { this.area = function() { return this.height * this.width / 2; }} 


Then, we direct the function. prototype attribute of a function to the instance created by another function. In this way, all objects created through the "sub-function" can obtain all the attributes defined by the "parent function" through the prototype chain.


In this example, the triangle object does not have the height and width attributes, so JavaScript will use the prototype chain to find them on the shape object. When we call triangle. when area () is used, the area () method of the triangle object is actually executed, rather than the shape object. Since the triangle object already has this attribute, you do not need to search for the prototype chain.





Add new attributes


One advantage of prototype inheritance is that you can easily add new attributes to an object so that all other objects that inherit this object along the prototype chain have this attribute. For example, we want to add a new method to Shape to calculate the perimeter. We may want to add this method to the Shape function, but as mentioned in the previous article, it won't work:

function Shape() {this.height = 10;this.width = 10;this.area = function() {return this.height * this.width;};};var shape = new Shape();console.log(shape.perimeter());  // TypeError: Object # has no method 'perimeter'Shape.perimeter = function() {return this.height * 2 + this.width * 2;};var shape1 = new Shape(); console.log(shape1.perimeter()); // TypeError: Object # has no method 'perimeter' 


In fact, we should directly give the function. this method is added to prototype, so that it is added to the prototype chain. This method is available to all instances created using the Shape () function.

Shape.prototype.perimeter = function() {   return this.height * 2 + this.width * 2;}console.log(shape.perimeter()); // 40 



So why can't I put this new method on the constructor of the created object? After a function is created, any attribute added to it will become a static attribute, which means that you can only access these attributes through the function itself, that is, Shape. perimeter (). In addition, static attributes are not added to instances created using this function. Therefore, if you want to add a new property, you can only use function. prototype (Note: In JavaScript, everything is an object, remember? Therefore, the function itself is also an object. constructors such as Shape and Triangle in the sample code are also objects, so you can directly add a method to the Shape as above, in fact, the result is to add a method to this function object, so it is certainly not in the prototype chain, so this will not affect the instances created using these constructor ).




Conclusion


For those familiar with class-based languages and who have just started JavaScript, its prototype mechanism is indeed confusing. However, since JavaScript is a prototype language, to fully understand how it works, you must first understand its prototype mechanism. Because different objects are linked together with prototype, you can search for this attribute without finding its expected attribute on an object.


In the next article, I will discuss some common mistakes and traps in JavaScript, and how to create a prototype chain more concisely and effectively.

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.