Not prototype inheritance so simple!! Prototype Deep exploration of _javascript skills

Source: Internet
Author: User
Tags abs visibility
1 What is prototype

The prototype property of an object in JavaScript that returns a reference to the object type prototype. This is a rather awkward explanation, and to understand it, the concept of object type (type) and prototype (prototype) should be understood first.
Before we say, an object's class and object instance (Instance) is a "create" relationship, so we think of "class" as a model of the object's characteristics, and the object is considered to be an embodiment of a class feature, or a class is a type of object (type). For example, in the previous example, the types of P1 and P2 are point, and in JavaScript, this can be verified by the instanceof operator:
P1 instanceof Point
P2 instanceof Point

However, point is not the only type of P1 and P2, because P1 and P2 are objects, so obejct is also their type, because object is a more generalized class than it is, so we say that there is a kind of derivation between the obejct, and then we know that, This kind of relation is called "inheritance", it is also a special case of the generalization relation between objects, and it is an indispensable basic relation in object oriented.
In the object-oriented domain, instances and types are not unique pairs of abstract relationships that can be described, and in JavaScript, another important abstract relationship is type and prototype (prototype). This relationship is a higher level of abstraction, which happens to form a three-layer chain with the abstract relation of the type and the instance, the following diagram describes the relationship:
Todo:

In real life, we often say that something is created with another thing as a prototype. These two things can be of the same type, or they can be of different types. Idiom "according to gourd painting ladle", the gourd here is the prototype, and the scoop is the type, with JavaScript prototype to say is "scoop." prototype = some gourd "or" scoop. Prototype= new Gourd ().
To understand the prototype in depth, we can study a design pattern of--prototype pattern, the core of which is to use the prototype instance to specify the type of object to create, and to create new objects by copying these prototypes. The prototype of JavaScript is similar to this way.

The details of prototype pattern can be referred to as "design mode" ("Designing Patterns") it is not the scope of this article.

Note that unlike the relationship between the type and the instance, the relationship between the stereotype and the type requires that a type can have only one prototype at a time (while an instance can obviously have multiple types at one time). For JavaScript, this restriction has two layers of meaning, the first is that each specific JavaScript type has and has only one prototype (prototype), which, by default, is an object (note that it is not the object type!). )。 Second, the type that this object belongs to must be a chain of types that satisfies the prototype relationship. For example, the type that P1 belongs to is point and object, and an object is the prototype of point. If there is an object that belongs to the type ClassA, CLASSB, CLASSC, and object, then the four classes must be satisfied to form a complete prototype chain, for example:
Todo:


The following diagram depicts the relationship between objects, types, and prototypes in javascript:
Todo:

Interestingly, JavaScript does not specify the type of stereotype of a type (which is a very awkward word), so it can be of any type, usually an object, so that the object-type-prototype (object) may form a ring-like structure, or some other interesting topology, These structures provide a variety of uses for JavaScript, some of which are ingenious and aesthetically pleasing. The following section focuses on the use of prototype.



2 Prototype Use Tips

Before you understand the prototype skills, first understand the characteristics of prototype. First, JavaScript provides a prototype attribute for each type (type), which points to an object, which becomes the "archetype" of this type, meaning that all objects created by this type have the characteristics of this prototype. In addition, the JavaScript object is dynamic, and the prototype is no exception, adding or decreasing attributes to the prototype will change this type of prototype, which will directly affect all objects created by the prototype, such as:
<script> function Point (x,y) {this.x = x; This.y = y; var p1 = new Point (1,2); var P2 = new Point (3,4); point.prototype.z = 0; The dynamically-point prototype adds attribute alert (P1.Z); alert (P2.Z); All objects created by the point type at the same time </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]


If a property named A is added to the prototype of an object, and the object itself has a property named a with the same name, the property of the object itself "overrides" the prototype property when accessing the object's property A, but the prototype property does not disappear. When you delete the property A of the object itself with the delete operator, the object's prototype property is restored to visibility. With this feature, you can set default values for the properties of an object, such as:
<script> function Point (x, y) {if (x) this.x = x; if (y) this.y = y; } point.prototype.x = 0; point.prototype.y = 0; var p1 = new Point; var P2 = new Point (1,2); </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]

The above example sets the default value (0,0) for the point object by prototype, so the P1 value is (0,0) and the P2 value is (1,2), with the delete p2.x, delete p2.y; The value of P2 can be restored to (0,0). Here's a more interesting example:
<script> function ClassA () {THIS.A = 100; this.b = 200; THIS.C = 300; This.reset = function () {for (var all in) {delete This[each]; }} classa.prototype = new ClassA (); var a = new ClassA (); alert (A.A); A.A *= 2; A.B *= 2; A.C *= 2; alert (A.A); alert (A.B); alert (A.C); A.reset (); Call the Reset method to revert the value of a to the default value of alert (A.A); alert (A.B); alert (A.C); </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]


You can also use prototype to set a read-only getter for the properties of an object, thus preventing it from being overwritten. Here is an example:
<script> function Point (x, y) {if (x) this.x = x; if (y) this.y = y; } point.prototype.x = 0; point.prototype.y = 0; function LineSegment (p1, p2) {//private member var m_firstpoint = p1; var m_lastpoint = p2; var m_width = {Valueof:function () {return Math.Abs (p1.x-p2.x)}, Tostring:function () {return Math. ABS (p1.x-p2.x)}} var m_height = {Valueof:function () {return Math.Abs (P1.Y-P2.Y)}, T Ostring:function () {return Math.Abs (P1.Y-P2.Y)}}//getter This.getfirstpoint = function () { return m_firstpoint; } this.getlastpoint = function () {return m_lastpoint; } this.length = {valueof:function () {return math.sqrt (M_width*m_width + m_height*m_height)}, Tostring:function () {return math.sqrt (M_width*m_width + M_height*m_height)}}} var p1 = new Point; var P2 = new Point (2,3); var line1 = new LineSegment (p1, p2); var LP = Line1.getfirstpoint (); lp.x = 100; Accidentally rewrote the LP's value, destroying the LP's original value and not restoring alert (Line1.getfirstpoint (). x); alert (line1.length); Even Line1.lenght has changed </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]


Rewrite the This.getfirstpoint () as follows:
This.getfirstpoint = function ()
{
function GETTER () {};
Getter.prototype = M_firstpoint;
return new GETTER ();
}
You can avoid this problem and ensure the M_firstpoint property is read-only.
<script> function Point (x, y) {if (x) this.x = x; if (y) this.y = y; } point.prototype.x = 0; point.prototype.y = 0; function LineSegment (p1, p2) {//private member var m_firstpoint = p1; var m_lastpoint = p2; var m_width = {Valueof:function () {return Math.Abs (p1.x-p2.x)}, Tostring:function () {return Math. ABS (p1.x-p2.x)}} var m_height = {Valueof:function () {return Math.Abs (P1.Y-P2.Y)}, T Ostring:function () {return Math.Abs (P1.Y-P2.Y)}}//getter This.getfirstpoint = function () { function GETTER () {}; Getter.prototype = M_firstpoint; return new GETTER (); } this.getlastpoint = function () {function GETTER () {}; Getter.prototype = m_LastPoint; return new GETTER (); } this.length = {valueof:function () {return math.sqrt (M_width*m_widtH + m_height*m_height)}, Tostring:function () {return math.sqrt (M_width*m_width + m_height*m_height)}} var p1 = new Point; var P2 = new Point (2,3); var line1 = new LineSegment (p1, p2); var LP = Line1.getfirstpoint (); lp.x = 100; Accidentally rewrote the LP's value, but did not destroy the original value alert (Line1.getfirstpoint (). x); alert (line1.length); Line1.lenght not changed </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]


In fact, you set an object as a prototype of a type, this is equivalent to creating a read-only copy of the object by instantiating it, and changing the copy at any time does not affect the original object, and changes to the original object affect the copy unless the changed attribute has been overwritten with the copy's own attribute of the same name. You can restore the visibility of a prototype property by deleting the object's own name with the delete operation. Let me give you an example:
<script> function Polygon () {var m_points = []; m_points = array.apply (m_points, arguments); function GETTER () {}; Getter.prototype = M_points[0]; This.firstpoint = new GETTER (); This.length = {Valueof:function () {return m_points.length}, Tostring:function () {return m_points.le Ngth}} this.add = function () {m_points.push.apply (m_points, arguments); } this.getpoint = function (idx) {return M_POINTS[IDX]; } this.setpoint = function (idx, point) {if (m_points[idx] = = null) {M_poin TS[IDX] = point; else {m_points[idx].x = Point.x; M_points[idx].y = Point.y; }} var p = new Polygon ({x:1, y:2},{x:2, Y:4},{x:2, y:6}); alert (p.length); alert (p.firstpoint.x); alert (P.FIRSTPOINT.Y); P.firstpoint.x = 100; Accidentally wrote its value alert (p.getpoinT (0). x); Does not affect the actual private member Delete p.firstpoint.x; Restore alert (p.firstpoint.x); P.setpoint (0, {x:3,y:4}); The actual Private member alert (P.firstpoint.x) is rewritten through a setter; The value of the Getter changed alert (p.getpoint (0). x); </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]


Note that the above example illustrates the use of prototype to quickly create multiple copies of an object, and generally, using prototype to create a large number of complex objects is much faster than copying objects in any other way. Note that using an object as a prototype to create a large number of new objects is precisely the essence of prototype pattern.
Here is an example:
<script> var p1 = new Point (1,2); var points = []; var pointprototype = function () {}; Pointprototype.prototype = p1; for (var i = 0; I < 10000 i++) {points[i] = new Pointprototype (); Because the Pointprototype constructor is an empty function, it is constructed much faster than a direct constructed//P1 copy. } </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]


In addition to the above mentioned techniques, prototype, for its unique characteristics and other uses, is used as the broadest and most widely known possibility to simulate inheritance, and this is left to be discussed in the next section.

3 The essence of prototype

It has already said the role of prototype, and now we are going to reveal the essence of prototype by law.
We say that prototype behaves like a static domain in C + +, adding a property as a prototype property that will be shared by all instances created by that type, but this share is read-only. In any instance, you can only overwrite this property with your own attribute with the same name, not change it. In other words, when an object reads a property, it always checks the property sheet of its own field, and if it does, it returns the property, otherwise it reads the prototype field and returns the properties on the Protoype field. In addition, JavaScript allows the protoype domain to reference any type of object, so if the property is still not found on the Protoype field, JavaScript will recursively find the prototype domain of the object that the prototype domain is pointing to. Until the prototype field of this object is itself or the loop is present, we can use the following diagram to describe the relationship between prototype and the object instance:
Todo:

The value and limitation of 4 prototype

From the above analysis we understand the prototype, through it can be an object as a prototype, security to create a large number of instances, which is the real meaning of prototype, but also its value. As we'll see later, this feature of prototype can be used to simulate the inheritance of objects, but it's important to know that prototype is used to simulate inheritance, though it's an essential value, but it's definitely not the core of it, in other words, JavaScript's support for prototype is not simply a way to implement its object inheritance, and even without prototype inheritance, the prototype mechanism of JavaScript is still very useful.
Because prototype only builds replicas of types with objects, it also has a lot of limitations. First, it does not represent a copy of a value in the prototype domain of a type, but rather a reference copy, which brings "side effects". Changing the attribute value of a reference type on a prototype (another rather awkward explanation: P) will completely affect each instance of the type creation. Sometimes this is exactly what we need (such as the default values for all objects of a certain class), but sometimes this is something we don't want (like when the class inherits), here's an example:
<script> function ClassA () {this.a=[]; function ClassB () {this.b=function () {}; } classb.prototype=new ClassA (); var objb1=new classb (); var objb2=new classb (); Objb1.a.push (1,2,3); alert (objb2.a); A member of all B's instances has changed!! This is not what this example wants to see. </script>
[Ctrl + A All SELECT Note: If the need to introduce external JS need to refresh to perform]

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.