Next: , Up: The Visibility Object

B.2.3.1 Visibility Object Implementation

The visibility object is mostly simply represented in the following diagram:


Figure B.13: Structure of the visibility object

Specifically, the visibility object is a prototype chain containing the private members of the class associated with the method currently being invoked on the current instance, its protected members (including those inherited from its supertype) and the public members (also including those inherited from the supertype). To accomplish this, the visibility object has the following properties:

As a consequence of the above, it is then clear that there must be a separate visibility object (prototype chain) for each supertype of each instance, because there must be a separate private object for each subtype of each instance. Let us consider for a moment why this is necessary with the following sample of code:

var C1 = Class(
        'private _name': 'Foo',

        'public getName': function()
            return this._name;

        // ...
    } ),

    // note the naming convention using descending ids for the discussion
    // following this example
    C0 = C1.extend(
        // ...
    } );

C1().getName(); // "Foo"
C0().getName(); // "Foo"

Figure B.14: Why private member swapping is necessary

Figure B.14 demonstrates why the private object swapping1 is indeed necessary. If a subtype does not override a super method that uses a private member, it is important that the private member be accessible to the method when it is called. In Figure B.14, if we did not swap out the object, _name would be undefined when invoked on C2.

Given this new information, the implementation would more formally be represented as a collection of objects V for class C and each of its supertypes as denoted by C\_n, with C\_0 representing the class having been instantiated and any integer n > 0 representing the closest supertype, such that each V\_n is associated with C\_n, V\_n\^x is the visibility object bound to any method associated with class C\_x and each V shares the same prototype chain P\_n for any given instance of C\_n:


Figure B.15: Collection of visibility objects V for each class C

Fortunately, as shown in Figure B.15, the majority of the prototype chain can be reused under various circumstances:

Consequently, on instantiation of class C\_n, we incur a performance hit from __initProps() for the initialization of each member of V\_x and P\_x, as well as each property of C\_x, recursively for each value of mxn (that is, supertypes are initialized first), where m is equal to the number of supertypes of class C\_n + 1.2

The instance stores a reference to each of the visibility objects V, indexed by an internal class identifier (which is simply incremented for each new class definition, much like we did with the instance id in Figure B.8). When a method is called, the visibility object that matches the class identifier associated with the invoked method is then passed as the context (bound to this) for that method (see Method Wrapping).


[1] The term “swapping” can be a bit deceptive. While we are swapping in the sense that we are passing an entirely new private object as the context to a method, we are not removing an object from the prototype chain and adding another in place of it. They do, however, share the same prototype chain.

[2] There is room for optimization in this implementation, which will be left for future versions of ease.js.