Prototype Chain

久々に JavaScript の仕事をすることになりました。今は prototype.js やら jQuery やらほんとにいろいろあって何も考えずにやれば何も考えずにできるのでしょうが、いまいち何をしているのかわからなくて不安なのでソースを読んでいたら、Prototype Chain の正確な話をまたしても忘れていた。

いっつもです。いっつも ECMAScript の Specification 見て「あーそういうことね」ってなってそのときはやって、そんですぐ忘れます。


Standard ECMA-262 3rd Edition - December 1999


4.2.1 Objects

ECMAScript does not contain proper classes such as those in C++, Smalltalk, or Java, but rather, supports constructors which create objects by executing code that allocates storage for the objects and initialises all or part of them by assigning initial values to their properties. All constructors are objects, but not all objects are constructors. Each constructor has a Prototype property that is used to implement prototype-based inheritance and shared properties. Objects are created by using constructors in new expressions; for example, new String("A String") creates a new String object. Invoking a constructor without using new has consequences that depend on the constructor. For example, String("A String") produces a primitive string, not an object.

ECMAScript supports prototype-based inheritance. Every constructor has an associated prototype, and every object created by that constructor has an implicit reference to the prototype (called the object’s prototype) associated with its constructor. Furthermore, a prototype may have a non-null implicit reference to its prototype, and so on; this is called the prototype chain. When a reference is made to a property in an object, that reference is to the property of that name in the first object in the prototype chain that contains a property of that name. In other words, first the object mentioned directly is examined for such a property; if that object contains the named property, that is the property to which the reference refers; if that object does not contain the named property, the prototype for that object is examined next; and so on.

In a class-based object-oriented language, in general, state is carried by instances, methods are carried by classes, and inheritance is only of structure and behaviour. In ECMAScript, the state and methods are carried by objects, and structure, behaviour, and state are all inherited.

All objects that do not directly contain a particular property that their prototype contains share that property and its value. The following diagram illustrates this:

CF is a constructor (and also an object). Five objects have been created by using new expressions: cf1,cf2,cf3,cf4,and cf5. Each of these objects contains properties named q1 and q2. The dashed lines represent the implicit prototype relationship; so, for example, cf3’s prototype is CFp. The constructor, CF, has two properties itself, named P1 and P2, which are not visible to CFp,cf1,cf2,cf3,cf4,orcf5.The property named CFP1 in CFp is shared by cf1,cf2,cf3,cf4,andcf5 (but not by CF), as are any properties found in CFp’s implicit prototype chain that are not named q1, q2, or CFP1. Notice that there is no implicit prototype link between CF and CFp.

Unlike class-based object languages, properties can be added to objects dynamically by assigning values to them. That is, constructors are not required to name or assign values to all or any of the constructed object’s properties. In the above diagram, one could add a new shared property for cf1, cf2, cf3, cf4,and cf5 by assigning a new value to the property in CFp.