Private Static Members in Javascript

Site Navigation 

Introduction

It was a widely held belief that javascript objects could not have private instance members, that all javascript object properties where public and could be accessed and changed with external code. Douglas Crockford has demonstrated that closures can be used to provide javascript objects with private members.

Douglas Crockford describes how the invocation of the constructor forms a closure that allows all of the parameters, local variables and any functions defined as function fncName(){ ... ); within the constructor to remain associated with the object that is constructed as its private members. And how inner functions assigned to properties of the object instance (with this.methodName = function(){ ... };) become "privileged" methods. Privileged because they have direct access to the private members of the object. Apart from invoking the privileged instance members of an object, there is no way that external code can access the private members of the object instance. Public members are assigned to the constructor's prototype object in the traditional way (but public methods have no direct access to the instance's private members).

Public and private are terms directly from class based languages (joined by "package" and "protected" in Java), privileged is a term that I think Mr Crockford coined to describe the special role of the constructor's inner functions assigned to externally accessible instance members.

In Java the modifiers private, public, package and protected can be combined with additional modifiers, one of which is static. A member that is static is a member of the Class and not the instance. There is only one copy of the member per Class. In javascript static members are defined as properties of the constructor:

function MyObject(){
   // constructor function
}

MyObject.staticMember = "any value";

Javascript static members defined as properties of the constructor object are public static members.

It was also widely believed that javascript static members must also always be public, even by people familiar with Douglas Crockford's technique for creating private instance members.

Private Static Members Associated with the Constructor.

Private instance members are achieved by forming a closure when objects are instantiated. It is possible to form a closure that included the class constructor and local variables that would serve as private class members by making a one-off inline function call that returned the constructor (there is only one constructor per class), as the page or JS file loaded.

var MyObject = (function(){
    /*private static (class) member*/
    var counter = 0;
    /*private static method.*/
    function incrementCounter(){
        return counter++;
    };
    /*class constructor.*/
    function constructorFn(id){
        this.id = id;
        var self = this;
        /*call private static (class)
        method and assign the returned
        index to a private instance member.*/
        var index = incrementCounter();
        /*privileged instance method.*/
        this.getIndex = function(){
            return index;
        };
    };
    /*privileged static (class) method
    (a property of the constructor)*/
    constructorFn.getNoOfInsts = function(){
        return counter;
    };
    /*public instance method privaliged at the
    class level*/
    constructorFn.prototype.pubInstMethod = function(){
        ...
    };
    /*return the constructor.*/
    return constructorFn;
})(); //simultaneously define and call (one-off)!

/*public static  member*/
MyObject.pubStatic = "anything"

/*public instance member*/
MyObject.prototype.pubInstVar = 8;

Having the one-off function call return the class constructor forms a closure that can hold private static members and assign privileged static methods (as properties of the returned constructor. This is essentially taking Douglas Crockford's method for creating private instance members and applying it to the constructor itself to produce the same effect at the class level.

In javascript inner functions have direct access to the parameters and local variables in their containing functions. In this case code within the constructor function can call the incrementCounter function as its name is a local variable name of the constructor's containing (outer) function.

There is an interesting side effect in that privileged instance methods become doubly privileged in that they also have direct access to the private static members of the class.

Public instance (defined as properties of the prototype) and static methods (properties of the constructor as returned by the inline function call) have no access to the private static members of the class.

Having taken the idea that made private instance members possible and applied it at a level that makes private static members possible the obvious next step is to apply the same method to groups of classes.

In class based languages a grouping of classes might be a package. I don't think that I would use package to describe groupings of classes in javascript. For one thing package members (private or otherwise) don't really exist, and for another, the recursive application of the principle allows for groupings of groupings of classes (and so on).

Remembering that each inner function has direct access to the parameters and local variables in its outer function(s) the result of grouping class constructors within a closure of their own, and possibly that closure within others, produces an unusual hierarchy of nested accessibility. An unexpected feature of javascript.

A hypothetical class grouping closure (anonymous in this case) might go like:-

var global = this;
(function(){
    var classGroupMember = 3;
    function privateToClassGroup(){
        /*this method could be a utilitiy
        for the classes in the group or used
        as an internal object constructor.*/
        ...
    };
    global.MyObject1 = function(){
        var privteStaticMember = 4;
        function privateStaticMethod(){
            ...
        };
        function constructorFn(id){
            ...
        };
        /*return the constructor.*/
        return constructorFn;
    }();  //simultaneously define and call!
    global.MyObject2 = function(){
        function constructorFn(id){
            ...
        };
        /*return the constructor.*/
        return constructorFn;
    }();  //simultaneously define and call!
    global.MyObject3 = function(){
        function constructorFn(id){
            ...
        };
        /*return the constructor.*/
        return constructorFn;
    }();  //simultaneously define and call!
})();  //simultaneously define and call!

Private Static Members Associated with the Prototype.

The above is a tidied up version of a contribution that I made to a thread in the comp.lang.javascript newsgroup with the subject "closures, what are they good for?" that represented the my first formal description of using a closure to create private static members in javascript. It works because all instances of a class share the same constructor so they can also share the same closure formed with the constructor.

Subsequently it occurred to me that all instances of a class also share the same prototype and that a closure associated with that prototype could also serve as a repository for values that could serve as private static members.

A prototype is usually an Object (though it could be a function) so the outer function that would return the prototype would normally return an object that had function properties. Those function properties would be inner functions of the function that returned the object and so be privileged in the sense that they would have access to the parameters and local variables of their outer function.

/*constructor function */
function MyObject(){
    ...
}

MyObject.prototype = (function(){
    /*private static (class) member*/
    var privateStaticProp = "anything";
    /*private static method .*/
    function privateStaticMethod = function(){
        ...
    }
    return ({
        /*These functions objects are shared by
        all instances that uses this prototype
        and they have access to the private static
        members within the closure that returns
        this object*/
        publicInstanceMethod:function(){
            ...
        },
        setSomething:function(s){
            privateStaticProp = s;
        }
    });
})();

/*public instance member*/
MyObject.prototype.pubInstVar = 8;

Forming a closure with the prototype might be suitable if there is no need for private instance members, or no need for inner functions of the constructor to have access to the private static members of a class. That is unlikely to be the case often but it is nice to know that there are actually two methods of providing javascript objects with private static members.

Private Static Members on the Scope Chain.

Additional delving into the mechanism behind closures suggested a third method of associating private static members with all of the objects created with a constructor. This time without the need for a closure at all (no function nesting, except for optional privileged methods).

When a function is executed it enters an "execution context" which is assigned a scope chain. That scope chain is largely defined as a result of a scope chain assigned to an internal [[scope]] property of the function object being executed, which is assigned when the function object is created. And the scope chain that is assigned to the [[scope]] property of a function object is the scope chain of the execution context in which that function object was created. Normally that process is automatic and you get the scope chain you get.

However, the javascript with statement acts by adding an object to the top of the scope chain during the execution of a statement (which may be a block statement). If a function expression is evaluated in the code block of a with statement it will result in the construction of a function object and that function object will be assigned a [[scope]] property that corresponds with the scope chain of the execution context at that time. With the object added to the scope chain by the with statement at its top.

So, if you explicitly add an object to the scope chain that is used to define the [[scope]] property of the constructor function it will be shared by the execution contexts of every invocation of the constructor and so will also appear on the scope chain of any functions declared within that constructor (or function expressions evaluated there).

Create the constructor function within the body of a with statement that adds an anonymous object to the current scope chain, by evaluating a function expression, and code within the constructor body can refer to the public properties of that object using unqualified identifiers, which will be resolved against the scope chain. Once the with statement terminates the only objects in a position to access the properties of that object will be the ones created with (or within) the constructor.

var MyObject;
/* The - with - statement adds an anonymous object to the scope chain
   of the current (global) execution context. Any function expressions
   evaluated within the block statement associated with the - with -
   statement will create a function object with that anonymous object
   added to the scope chain assigned to its [[scope]] property, which
   will then be used when constructing a scope chain for its execution
   contexts. Because the [[scope]] property of the constructor will
   include the anonymous object so will any function objects
   constructed during its execution.
*/
with({
        prStatString:"anything",
        prStatNumber:4,
        prStatMethod:function(){
           /* This method can access the other properties of the object
              added to the scope chain of the constructor using the -
              this - keyword.
            */
            ...
        }
     }){
    /* The constructor has to be created within the - with - statement
       to have the anonymous object added to its scope chain:-
    */
    MyObject = (function(){
        /* The public properties of the object added to the scope chain
           of the constructor can be accessed by identifier alone. In
           this case the identifier - prStatNumber - is used to assign
           a default value to a private instance member:-
        */
        var prInstNum = prStatNumber;
        this.privMethod = (function(){
            /* Privileged methods created within the constructor will
               also have the anonymous object on their scope chain so
               the properties of that object may be accessed with
               unqualified identifiers form within this code.
            */
            ...
        });
        /* Executing private static methods is just a matter of
           executing them, but they will be executed as method of the
           object added to the scope chain.
        */
        prStatMethod();
        ...
    });
    /* Within the - with - statement any other function object created
       will also have the anonymous object on its scope chain.
    */
    MyObject.prototype.pubMethod = (function(){
        ...
    });
}

var testObj = new MyObject();

The with statement is generally looked down upon as being at the root of some bad coding practices. Up until this time I don't think I had ever used it in anger, so it is a bit unexpected to find what looks like a legitimate use for it.

Note: This scope chain augmentation is sound by ECMA 262 3rd edition but the 2nd edition did not define the [[scope]] property of function objects or specify how a scope chain was constructed. Netscape 4 has problems with some aspects of this process. Later ECMAScript versions would resolve unqualified identifiers against both the objects in its scope chain and the prototypes of those objects. Netscape 4 does not consider the prototypes of objects when resolving identifiers against its scope chain.

The technique used above still works with Netscape 4 (and hopefully other ECMAScript 2nd edition implementations) because it only employs properties created directly on the object added to the scope chain. The difference would arise if the identifier toString, for example, were to be used. The 3rd edition implementations would resolve it against the object's prototype and find Object.prototype.toString, while Netscape 4 would not consider the prototype when resolving that identifier.

Protected Instance Members in Javascript

To date nobody has come up with any reason for implementing protected members with javascript objects. I have made various attempts to demonstrate that the concept could be implemented in the event that some need to do so was identified, but my early efforts were flawed. The first could easily be circumvented and the later attempts imposed a considerable overhead on the executing code.

However, the preceding scope chain augmentation method suggested a way of implementing protected instance members with a considerably reduced overhead, much simpler verification of various objects rights to interact and more direct internal employment of the protected members.

There is no easy direct analogy between the concept of protected in a class-based language and anything that is meaningful in javascript. There are, for example, no packages, so it isn't meaningful to talk of restricting access to object members to classes within the same package (strictly there are no classes either). Instead the goal here is to implement a property storage area within an object instance that is not normally publicly exposed but that can be exposed by an object that is an instance of the same "class" (or group of "classes"). Restricting particular object interactions to within a pre-defined group of objects.

The following code demonstrates an object in which each instance has a private storage area for protected members and that storage area incorporates a mechanism for exposing the protected members on one instance to another. All objects (though they would not have to be objects of the same "class") that share the same protected storage mechanism are capable of exposing the protected members of all other instances using that mechanism.

A closure based private static inner class is used to create objects that will act as the protected storage area, but those objects create themselves as part of a linked structure so each has an ability to retrieve references to any of the others. A new instance of one of these linked objects is added to the scope chain of a unique constructor function created whenever an instance of the final class is created, and it serves as the repository of the instance's protected members. The public members of that linked object become available to the code within the constructor using an unqualified identifier in place of the linked object's property names.

When one object instance wants access to the protected members of another it calls a method of the linked object, using an unqualified identifier that corresponds with the retrieval method's name, passing a reference to itself and to the object that it wishes to interact with. That function verifies that the first object is entitled to perform the interaction and, if so, searches the chain of linked objects until it finds the one that corresponds with the second object, returning a reference to it that the first object can employ directly.

The result is that members that the code of one object is interacting with as if they were internal can be exposed to a select group of other objects as if they were public. A relatively simple implementation of the concept of protected in javascript objects.

Unfortunately there are practical constraints on the implementation that mean it is not possible to directly provide a constructor function for the "class", because each instance has a new constructor created for it (so that it may have a unique scope chain). As a result the function that returns the object instances must be a factory function.

var ProtectedObjectFactory = (function(){
    /* Inner class facilitating the implementation of
       protected members:-
    */
    var ScopeLinkedObj = (function(){
        /* The (private static) - base - member is initially assigned
           an object literal that is to act as the final significant
           object on the scope chain used to link instances of -
           ScopeLinkedObj - and its - getProtected - method will do no
           more than terminate the chain of execution of - getProtected
           - methods by returning null.
        */
        var base = {getProtected:function(){return null;}};
        /* This function will act as the constructor for instances of -
           ScopeLinkedObj - :-
        */
        function contr(){
            /* Adding the _current_ - base - object to the scope chain
               of the execution context of the constructor call adds
               the base object to the scope chain assigned to the
               internal [[scope]] property of the function object
               created within the - with - statement and assigned to
               the public - getProtected - property of the constructed
               object. As a result that function can call the -
               getProtected - method of the current base object as -
               getProtected(otherObj) - and leave it to the scope chain
               resolution of the identifier - getProtected - to find
               the correct object; the next instance of -
               ScopeLinkedObj - in the scope chain of this instance's -
               getProtected - method.
            */
            with(base){
                this.getProtected = function(otherObj){
                    /* The identifier - getProtected - should
                       scope-resolve to a named property of the current
                       - base - object:-
                    */
                    return (this.objInst&&(this.objInst == otherObj)&&
                             this)||//if object corresponds return this
                             getProtected(otherObj); // else check next
                }
            }
            /* Set - base - object to - this - object so that the next
               invocation of the constructor adds the object currently
               being constructed to the scope chain of the -
               getProtected - method/function it creates:-
            */
            base = this;
            /* Implicitly return the constructed object. */
        }
        /* Creating a specific prototype for the - ScopeLinkedObj -
           allows only one function object to provide the -
           exposeProtectedMembers - method for all of the instances of
           - ScopeLinkedObj - :-
        */
        contr.prototype = {
            /* This function is only interested in the public
               properties of an instance of - ScopeLinkedObj - and the
               private static - base - member of its class so one
               prototyped function is all that is needed.
            */
            exposeProtectedMembers:function(idObj, otherObj){
                /* First confirm that the calling function was in a
                   position to pass a reference to the object instance
                   (idObj) which had this - ScopeLinkedObj - object in
                   the scope chain of its constructor.


                */
                return ((this.objInst&&idObj&&(this.objInst == idObj)&&
                        /* If so, call the - getProtected - method of
                           the - ScopeLinkedObj - instance currently
                           assigned to the private static - base -
                           member. The - getProtected - call will
                           propagate through all existing instances of
                           - ScopeLinkedObj - until one of their public
                           - objInst - properties corresponds with the
                           - otherObj - parameter (at which point the
                           corresponding - ScopeLinkedObj - is
                           returned) or the initial default - base -
                           object is encountered at the end of the
                           chain:-
                        */
                        base.getProtected(otherObj))||
                        /* Else return null as the - idObj - was not
                           entitled to expose the protected members of
                           - otherObj - or the -
                           base.getProtected(otherObj) - call returned
                           null:-
                        */
                        null);
            },
            /* Default all property names used. If properties are not
               created either on this prototype or on the object itself
               the identifier resolution in the functions that have
               this object on their scope chain will not find
               properties on this object:-
            */
            protectedTestVal:null,
            protectedMethod:null,
            objInst:NaN //: so it won't equal anything if not set.
        };
        return contr;
    })();
    var consct,
        /* prototype object for all objects constructed */
        objProto = {
            /* Because a new constructor is to be created for each
               object instantiation any common (public) functionality
               that does not require access to the private or protected
               members of an object instance would be best defined on a
               (this) single object and then that object assigned as
               the prototype of each constructor created in turn.
            */

            // Define prototype members here.
        };
    /* The following statement returns the factory method used to
       create instances of the object that implements protected
       instance members:-
    */
    return (function(testVal){
        /* Create a new linked object to add to the [[scope]] chain
           for the following (constructor) function expression.

           Once the - with - statement terminates there will be no
           directly accessible references to the ScopeLinkedObj left
           available:-
        */
        with(new ScopeLinkedObj()){
            consct = (function(testVal){
                /* Assign a reference to the object being constructed
                   to a private - self - member so that private method
                   have a means of referring to the object instance (as
                   they cannot use the - this - keyword for that task.)
                   If a private method needs to call the -
                   exposeProtectedMembers - method it should use - self
                   - as the first parameter (and never - objInst -):-
                */
                var self = this;
                /* The following identifier should resolve as a
                   property of the - ScopeLinkedObj - and should be
                   assigned a reference to the - this - object so that
                   its - exposeProtectedMembers - method can verify
                   that it was this object that called it

                   Its only role is in the verification of access
                   rights to the protected properties. It should not
                   be re-set, read or referenced at all by code within
                   this constructor function. References to the object
                   instance should use the - self - reference or the -
                   this - reference depending on their context.

                   Code assigned to an instance of - ScopeLinkedObj -
                   or its prototype may use - this.objInst - to refer
                   to the object instance with which it is associated
                   but that code would not appear within this
                   constructor function:-
                */
                objInst = this;
                /* Assign the constructor's parameter to a protected
                   member as an example of usage:-
                */
                protectedTestVal = testVal;
                /* create a protected method:- */
                protectedMethod = function(){
                    /* This code can act on public members of this
                       object using the - self - variable. The
                       protected members with their unqualified
                       identifiers and the private members with their
                       unqualified identifiers.

                       It can be called as a public property of the
                       object returned by a call to -
                       exposeProtectedMembers - and a reference to it
                       may be kept by another object to allow its
                       remote execution.
                    */
                    ; //: protected method function body.
                };
                var privateTestVal;
                this.getFromOther = function(otherObj){
                    /* The call to the - exposeProtectedMembers -
                       method must pass the - this - keyword as its
                       first argument instead of - objInst - so the
                       function cannot be hijacked (executed as a
                       function (globally) or assigned as a method of a
                       different (and unrelated) object (such an object
                       would not be able to pass - this - as the object
                       that has been assigned to the objInst property
                       of the - ScopeLinkeObj - object in the
                       function's scope chain)):-
                     */
                    var protectedDat = exposeProtectedMembers(this,
                                                             otherObj);
                    /* The returned value may be null if access was
                       denied so the result must be tested to verify
                       that it is safe to act on it:-
                    */
                    if(protectedDat){
/* alert the accessed protected member to verify that it is working,
   if tested on a web browser (else there may be no alert function):-
*/
alert('protectedDat.protectedTestVal = '+protectedDat.protectedTestVal)
                        /* If an object is returned by the call to -
                           exposeProtectedMembers - the public
                           properties of that object are the protected
                           members of the - otherObj - object passed as
                           the argument to this method call. As such
                           they can be read and set directly, and
                           method of that object called, though those
                           method will execute as method of that object
                           and need to suitably implemented in order to
                           influence the - otherObj - object corectly.
                        */
                        privateTestVal = protectedDat.protectedTestVal;
                    }
                };
            }); //: end of constructor function body.
        } /*: end of - with - statement, the - ScopeLinkedObj - is
              removed form the scope chain of the execution context.
              Leaving the only means of accessing it as the -
              exposeProtectedMembers - method.
          */
        /* Let all constructed objects share a common prototype by
           assigning the same object to the prototype of each
           constructor function created:-
        */
        consct.prototype = objProto;
        /* Construct and return the new object:-
        */
        return new consct(testVal);
    }); //: end of factory function body.
})();

var a = ProtectedObjectFactory(4);
var b1 = ProtectedObjectFactory(8);
var b2 = ProtectedObjectFactory(6);
var b3 = ProtectedObjectFactory(7);
var b4 = ProtectedObjectFactory(5);

//a.getFromOther(b1); // should alert 8
//a.getFromOther(b2); // should alert 6
a.getFromOther(b3); // should alert 7
//a.getFromOther(b4); // should alert 5

If the outer function expression assigned multiple factory function for the creation of several classes of object, instead of directly returning just one, and all of those classes employed the same protected member implementation, then instances of those multiple classes would be able to interact in a way denied to other classes. Extending the protected concept towards the package level.

But as I have said, nobody has found a real need to implement a concept of protected members in javascript. However, of more immediate practical interest may be the object used to implement the protected storage, particularly the way it achieves its chain-like linkage using customised scope chains. I can see many interesting chain and tree structures being built around an elaboration of that approach (particularly if you also consider the role of the object's prototypes in identifier resolution on the scope chain).

Note: Exactly the same ECMAScript version considerations that apply to implementing private static members with the scope chain apply to the above process. But the above code does directly employ the prototype of the objects added to the scope chains. Netscape 4 fails with that version because it misses the properties of the prototype when resolving identifiers. The solution is to modify the design of the ScopeLinkedObj object so that its properties are directly defined on the objects created instead of inherited from their prototype.

The following is a version that works with Netscape 4 (and hopefully other ECMA 262 2nd edition implementations) and all ECMAScript 3rd edition implementations:-

var ProtectedObjectFactory = (function(){
    /* Inner class facilitating the implementation of
       protected members:-
    */
    var ScopeLinkedObj = (function(){
        var base = {getProtected:function(){return null;}};
        /* Because this version must actively assign all of the
           properties of the - ScopeLinkedObj - directly to the object,
           the prototype is no longer used and cannot provide a common
           - exposeProtectedMembers -, but it is still unnecessary to
           create a separate function to act as the method for each
           object. Instead a private static method is going to be used,
           defined here and assigned to the - exposeProtectedMembers -
           property of each object as it is constructed:-
        */
        function expProt(idObj, otherObj){
            return ((this.objInst&&idObj&&(this.objInst == idObj)&&
                    base.getProtected(otherObj))||
                    null);
        }
        /* This function will act as the constructor for instances of -
           ScopeLinkedObj - but because the problem with Netscape 4,
           and possibly other ECMAScript 2nd edition implementations,
           do not recognise properties on the prototype of objects on
           the scope chain, so no prototype is being assigned to the
           constructor this time, the constructor function can be
           anonymous and directly returned from this inline function
           call:-
        */
        return (function contr(){
            with(base){
                this.getProtected = function(otherObj){
                    return (this.objInst&&(this.objInst == otherObj)&&
                            this)||getProtected(otherObj);
                }
            }
            /* The private static - expProt - function is assigned by
               reference to the - exposeProtectedMembers - property of
               each - ScopeLinkedObj - created. It is no longer defined
               on a prototype but there is still only one function
               object being shared by all instances of -
               ScopeLinkedObj - :-
            */
            this.exposeProtectedMembers = expProt;
            /* All of the other properties that were defaulted on the
               prototype in the preceding version are now need to be
               defined on the object itself:-
            */
            this.protectedTestVal = null;
            this.protectedMethod = null;
            this.objInst = NaN;

            base = this;
        });
    })();
    var consct,
        objProto = {
            // Define prototype members here.
        };
    return (function(testVal){
        with(new ScopeLinkedObj()){
            consct = (function(testVal){
                var self = this;
                objInst = this;
                protectedTestVal = testVal;
                protectedMethod = function(){
                    ; //: protected method function body.
                };
                var privatetestVal;
                this.getFromOther = function(otherObj){
                    var protectedDat = exposeProtectedMembers(this,
                                                          otherObj);
                    if(protectedDat){
                        privatetestVal = protectedDat.protectedTestVal;
                    }
                };
            }); //: end of constructor function body.
        }
        consct.prototype = objProto;
        return new consct(testVal);
    }); //: end of factory function body.
})();

Note: General.

A drawback of creating a closure associated with the constructor is that the constructor functions are created inline as the page loads. This means that any constructor returning function call cannot use a constructor or function that will be returned by a later function call. The order of loading must be considered so that constructor returning function calls happen after similar calls that they are dependent upon.

This is not the case for constructors defined with the standard function declarations as the creation of function objects from declarations precedes the execution of inline code.

The code that sets up prototypes is normally executed inline so associating private static members with a prototype does not differ significantly from normal assignments to the prototype.

Experiments to test the relative speed of identifier resolution suggest that it is fractionally faster to resolve private members (which are local variables of outer functions) than it is for public members accessed with this.propName. The difference is tiny and may not hold in all language implementations, but if performance is critical (as it may be with DHTML animation) then using private members instead of public should provide a small optimisation.

Note: Inheritance.

Douglas Crockford's technique for providing javascript objects with private static members has an impact on the way inheritance works with these objects.

Javascript inheritance is prototype based and usually a class inherits behaviour from a superclass by having an instance of that superclass assigned to its constructor's prototype property.

function MyObject1(){
    this.exampleProp1 = "anything";
}

MyObject1.prototype.publicMethod1 = function(){
    ...
}

function MyObject2(){
    this.exampleProp2 = "something";
}

MyObject2.prototype = new MyObject1();

MyObject2.prototype.publicMethod2 = function(){
    ...
};

var obj = newMyObject2(); //Instance of MyObject2

The code above assigns an instance of MyObject1 to the prototype of MyObject2 and as a result instances of MyObject2 inherit the public members of MyObject1. Named property resolution involves searching the object itself for a property with the corresponding name and then, if not found, searching the prototype for a property with the name, and then the prototype of the prototype, and so on.

So obj.exampleProp2 is resolved as a property of the MyObject2 instance. While obj.exampleProp1 is resolved as a property of MyObject2's prototype, the instance of MyObject1 that has been assigned to MyObject2's prototype. obj.publicMethod2 is also resolved as a property of MyObject2's prototype, and it is a property of the instance of MyObject1 that has been assigned as the prototype because it has been added to that object instance. It is unknown to the MyObject1 class (and its other instances, if any). Finally, obj.publicMethod1 would be resolved as a property of the prototype of the prototype of MyObject2 (the prototype of MyObject1). In this way MyObject2 has acquired all of the public properties of MyObject1 and added its own.

The problem arises when a closure associated with the object instance is being used to provide private instance members because assigning an instance of that object to the prototype of another constructor will only result in one closure being formed. The privileged methods of the object instance on the prototype are "inherited" by objects created with the constructor but they all access the same, single, closure. You may recognise that as exactly the characteristic exploited above in order to provide private static members associated with the prototype.

The solution is to adopt a different approach to inheritance and unsurprisingly Douglas Crockford has also addressed inheritance with a page on various possible inheritance patterns that can be implemented in javascript, including approaches that allow all instances of a class that wants to inherit from a class that uses private instance members to be associated with a closure identical to the closure that would be created for instances of their superclass.

Classes using my techniques for producing private static members do not suffer from any additional problems as a result. When a closure is associated with a constructor that uses Mr Crockford's technique then exactly the same considerations apply as when private static members are not being used. When the closure is associated with the prototype, or the returned constructor does not use a closure itself to provide private instance members, then inheritance by assigning an object instance to the prototype of another constructor will work exactly as it normally does.

Note: The Applicability of the Terminology from Class-Based Languages to Javascript.

All of the preceding text uses terminology from class-based languages and relates to concepts that are normally associated with those languages. The javascript language has no concept of "class". The nearest javascript gets to a class (and so, the definition of a class) is the code that represents a function that is used as a constructor and the code that defines the prototype that is associated with that constructor. And (with the code within the functions that return the constructor and/or prototype to facilitate the private static members) that is the javascript code structure that I have been using as if it was a class in a class-based language (taken as a whole: the class definition).

In a class-based language a class is defined in the source code and is absolutely fixed while the code is executing. In javascript all objects are mutable. Any property can be added to any object at any time and prototypes can be extended, replaced, swapped and so on. So the combination of a constructor function and its prototype could not be considered a class definition if the object instances, or the prototype were subject to modification at run-time. The concept of class no longer fits.

This run-time flexibility is a strength of javascript and it should not be denied or avoided out of a dogmatic belief that a class-based approach is intrinsically superior. The terminology from class-based languages can be used as a convenient description for concepts that are analogous both in design and use. But it should be recognised that they are not part of the language and "class" cannot be applied meaningfully to all javascript objects.

While this flexibility exists in practice there is little reason to be significantly modifying structures that could otherwise be considered analogous to a "class" at run-time. But I think that if and/or when it is advantageous to abandon the concept of fixed class definitions and exploit the flexibility inherent in the language then I can see no reason for not doing so.

The techniques for providing private members for javascript objects and "classes" are not a demonstration that javascript possesses these features as part of the language, they are a demonstration that it is easy to emulate private members with javascript. Of course when an emulation of something is sufficiently indistinguishable from that thing what does it matter that it is an emulation?

Written by Richard Cornford May 2003, expanded January 2004 and again in March 2004.

© Richard Cornford 2004