Home > Web Front-end > JS Tutorial > It's not as simple as prototypal inheritance! ! In-depth exploration of prototype_javascript skills

It's not as simple as prototypal inheritance! ! In-depth exploration of prototype_javascript skills

WBOY
Release: 2016-05-16 19:14:22
Original
1139 people have browsed it

1 What is prototype

The prototype attribute of an object in JavaScript can return a reference to the prototype of the object type. This is a rather confusing explanation. To understand it, you must first correctly understand the concepts of object type (Type) and prototype (prototype).
We said earlier that there is a "creation" relationship between an object's class (Class) and an object instance (Instance). Therefore, we regard "class" as a modeling of object characteristics, and objects as classes. The embodiment of characteristics, or class (Class) is a type (Type) of an object. For example, in the previous example, the types of p1 and p2 are both Point. In JavaScript, this can be verified through 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 both objects, Object is also their type. Because Object is a more general class than Point, we say that there is a derived relationship between Object and Point. We will know later that this relationship is called "inheritance". It is also a special case of the generalized relationship between objects and is an indispensable basic relationship in object-oriented.
In the object-oriented field, instance and type are not the only pair of describable abstract relationships. In JavaScript, another important abstract relationship is type (Type) and prototype (prototype). This relationship is a higher level of abstract relationship. It happens to form a three -layer chain with the abstract relationship between the type and the instance. > In real life, we often say that something is based on another thing. These two things can be of the same type or different types. The idiom "follow the gourd and draw the gourd", the gourd here is the prototype, and the gourd is the type. Using JavaScript's prototype to represent it is "ladle.prototype = a certain gourd" or "ladle.prototype = new gourd ()".
To deeply understand prototype, you can study one of its design patterns - prototype pattern. The core of this pattern is to use prototype instances to specify the types of objects to be created, and to create new objects by copying these prototypes. JavaScript prototype is similar to this method.

For details about prototype pattern, please refer to "Design Patterns" ("Design Patterns"), which is beyond the scope of this article.

Note that, unlike the relationship between types and instances, the relationship between prototypes and types requires that a type can only have one prototype at a time (and an instance can obviously have multiple types at a time). For JavaScript, this restriction has two meanings. The first is that each specific JavaScript type has and has only one prototype. By default, this prototype is an Object object (note that it is not an Object type!) . The second is that the type to which this object belongs must be a type chain that satisfies the prototype relationship. For example, the types of p1 are Point and Object, and an Object object is the prototype of Point. If there is an object whose types are ClassA, ClassB, ClassC and Object, then these four classes must form a complete prototype chain, for example:
                                     //TODO:


The following figure describes the relationship between objects, types and prototypes in JavaScript:
//TODO:

Interestingly, JavaScript does not specify the type of prototype of a type (this is again A very awkward sentence), so it can be any type, usually some kind of object. In this way, the object-type-prototype (object) may form a ring structure, or other interesting topological structures, which bring JavaScript It can be used in a variety of ways, some of which are not only clever but also full of beauty. The following section mainly introduces the usage of prototype.



2 Tips on using prototypes

Before understanding the tips on using prototypes, you must first understand the characteristics of prototypes. First of all, JavaScript provides a prototype attribute for each type (Type). Point this attribute to an object, and this object becomes the "prototype" of this type, which means that all objects created by this type have this Characteristics of the prototype. In addition, JavaScript objects are dynamic, and prototypes are no exception. Adding or subtracting attributes to prototype will change the prototype of this type. This change will directly affect all objects created by this prototype, for example:


[Ctrl A Select all Note: If you need to introduce external Js, you need to refresh it to execute
]


If you give someone A property named a is added to the prototype of an object type, and the object itself has a property with the same name named a. When accessing the property a of this object, the properties of the object itself "overwrite" the prototype property. , but the prototype properties do not disappear. When you use the delete operator to delete the property a of the object itself, the prototype properties of the object regain visibility. Using this feature, you can set default values ​​for the properties of the object, for example:

[Ctrl A Select all Note:
If you need to introduce external Js, you need to refresh to execute
]
The above example is prototyped as The Point object has a default value (0,0), so the value of p1 is (0,0) and the value of p2 is (1,2). The value of p2 can be changed by delete p2.x, delete p2.y; Return to (0,0). Here is a more interesting example:
[Ctrl A select all Note: <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; //动态为Point的原型添加了属性 alert(p1.z); alert(p2.z); //同时作用于Point类型创建的所有对象 </script>If you need to introduce external Js, you need to refresh to execute <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>]<script> function classA() { this.a = 100; this.b = 200; this.c = 300; this.reset = function() { for(var each in this) { 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(); //调用reset方法将a的值恢复为默认值 alert(a.a); alert(a.b); alert(a.c); </script>   

利用prototype还可以为对象的属性设置一个只读的getter,从而避免它被改写。下面是一个例子: 

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]
   

将this.getFirstPoint()改写为下面这个样子:
this.getFirstPoint = function()
{
        function GETTER(){};
        GETTER.prototype = m_firstPoint;
        return new GETTER();
}
则可以避免这个问题,保证了m_firstPoint属性的只读性。 

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]
   

实际上,将一个对象设置为一个类型的原型,相当于通过实例化这个类型,为对象建立只读副本,在任何时候对副本进行改变,都不会影响到原始对象,而对原始对象进行改变,则会影响到副本,除非被改变的属性已经被副本自己的同名属性覆盖。用delete操作将对象自己的同名属性删除,则可以恢复原型属性的可见性。下面再举一个例子: 

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]
   

注意,以上的例子说明了用prototype可以快速创建对象的多个副本,一般情况下,利用prototype来大量的创建复杂对象,要比用其他任何方法来copy对象快得多。注意到,用一个对象为原型,来创建大量的新对象,这正是prototype pattern的本质。
下面是一个例子: 

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]
   

除了上面所说的这些使用技巧之外,prototype因为它独特的特性,还有其它一些用途,被用作最广泛和最广为人知的可能是用它来模拟继承,关于这一点,留待下一节中去讨论。

3 prototype的实质

        上面已经说了prototype的作用,现在我们来透过规律揭示prototype的实质。
        我们说,prototype的行为类似于C++中的静态域,将一个属性添加为prototype的属性,这个属性将被该类型创建的所有实例所共享,但是这种共享是只读的。在任何一个实例中只能够用自己的同名属性覆盖这个属性,而不能够改变它。换句话说,对象在读取某个属性时,总是先检查自身域的属性表,如果有这个属性,则会返回这个属性,否则就去读取prototype域,返回protoype域上的属性。另外,JavaScript允许protoype域引用任何类型的对象,因此,如果对protoype域的读取依然没有找到这个属性,则JavaScript将递归地查找prototype域所指向对象的prototype域,直到这个对象的prototype域为它本身或者出现循环为止,我们可以用下面的图来描述prototype与对象实例之间的关系:
        //TODO:

4 prototype的价值与局限性

        从上面的分析我们理解了prototype,通过它能够以一个对象为原型,安全地创建大量的实例,这就是prototype的真正含义,也是它的价值所在。后面我们会看到,利用prototype的这个特性,可以用来模拟对象的继承,但是要知道,prototype用来模拟继承尽管也是它的一个重要价值,但是绝对不是它的核心,换句话说,JavaScript之所以支持prototype,绝对不是仅仅用来实现它的对象继承,即使没有了prototype继承,JavaScript的prototype机制依然是非常有用的。
        由于prototype仅仅是以对象为原型给类型构建副本,因此它也具有很大的局限性。首先,它在类型的prototype域上并不是表现为一种值拷贝,而是一种引用拷贝,这带来了“副作用”。改变某个原型上引用类型的属性的属性值(又是一个相当拗口的解释:P),将会彻底影响到这个类型创建的每一个实例。有的时候这正是我们需要的(比如某一类所有对象的改变默认值),但有的时候这也是我们所不希望的(比如在类继承的时候),下面给出了一个例子:

[Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template