JavaScript Magic Properties: Using __count__ , __proto__ , and __parent__

 

Two of the Mozilla implementations of the JavaScript engine, SpiderMonkey and Rhino, support a special list of magic properties. Because SpiderMonkey is the JavaScript engine used by Firefox, this means that you can use these magic properties in JavaScript code that is executed within the Firefox browser. Unfortunately, these magic properties are not supported by Microsoft Internet Explorer or Opera. There is no expectation that any browser other than a Mozilla browser will ever support these properties since the properties are not part of the ECMAScript standard that defines the JavaScript standard.

So why should you care about these properties? Since Internet Explorer does not support these properties, and Internet Explorer dominates the browser market, these properties should not be used in code consumed by the public. However, these properties can be useful as “explaining” properties. They can be used to further our understanding of how the JavaScript engine works under the hood.

Understanding __count__

Let’s start with the __count__ property. The __count__ property returns the number of properties (and methods) supported by an object. For example, executing the following code in the Firefox browser displays the number 3:

   1:  var myObject = 
   2:   
   3:  {
   4:   
   5:  prop1: "Hello",
   6:   
   7:  prop2: "World",
   8:   
   9:  doSomething: function() { return this.prop1 + " " + this.prop2} 
  10:   
  11:  };
  12:   
  13:  alert(myObject.__count__ );

The __count__ property only returns the immediate properties of an object. The __count__ property won’t count properties in the object’s prototype chain. For example, the following script creates two constructor functions named Thing1 and Thing2. Thing1 inherits from Thing2 using prototype inheritance. The variable it is created as an instance of Thing1. However, when __count__ is used with it, __count__ returns the value 1 (completely ignoring Thing2):

   1:  <script type="text/ecmascript">
   2:   
   3:  // Define Thing1
   4:   
   5:  function Thing1()
   6:   
   7:  {
   8:   
   9:    this.prop1 = "hello";
  10:   
  11:  }
  12:   
  13:  // Define Thing2
  14:   
  15:  function Thing2()
  16:   
  17:  {
  18:   
  19:    this.prop2 = "world";
  20:   
  21:  }
  22:   
  23:  // Set Thing1 prototype
  24:   
  25:  Thing1.prototype = new Thing2();
  26:   
  27:  // Instantiate a Thing1
  28:   
  29:  var it = new Thing1();
  30:   
  31:  // Count properties (returns 1)
  32:   
  33:  alert(it.__count__);
  34:   
  35:  </script>

It is important to remember that JavaScript objects are dynamic: the properties and methods supported by an object can be modified at any time during runtime. You can modify JavaScript objects in this way because JavaScript objects are basically hash tables. For example, the following script displays different values for the __count__ property for the very same object:

   1:  <script type="text/javascript">
   2:   
   3:  var thing = {};
   4:   
   5:  document.write(thing.__count__ + "<br />"); // returns 0
   6:   
   7:  thing.someProp = "hello";
   8:   
   9:  document.write(thing.__count__ + "<br />"); // returns 1
  10:   
  11:  thing.someProp == undefined;
  12:   
  13:  document.write(thing.__count__ + "<br />"); // returns 1
  14:   
  15:  delete thing.someProp;
  16:   
  17:  document.write(thing.__count__ + "<br />"); // returns 0
  18:   
  19:  </script>

Notice that assigning the value undefined to a JavaScript property does not remove the property. In order to remove a property, you must explicitly use the delete operator.

The __count__ property only works for user created objects. I was disappointed that the following script did not work:

   1:  <script type="text/javascript">
   2:   
   3:  var d = new Date();
   4:   
   5:  alert( d.__count__ );
   6:   
   7:  </script>
   8:   

When you execute the script above, the value 0 is displayed.

Using __proto__

The __proto__ property enables you to access an object’s prototype object. JavaScript, unlike languages such as C# and VB.NET, does not support class inheritance. Instead, JavaScript supports a more powerful type of inheritance called prototype inheritance. Class inheritance is limited. When using class inheritance, an object can inherit only structure and behavior. Prototype inheritance, on the other hand, enables an object to inherit structure, behavior, and state from a parent object.

Any object can have a prototype object associated with it. The prototype object, in turn, can have its own prototype object. This sequence of prototypes makes up the object’s prototype chain. For example, the following script instantiates an object named rover. Rover is an instance of a Dog. A Dog is an instance of an Animal:

   1:  <script type="text/javascript">
   2:   
   3:  function Animal()
   4:   
   5:  {
   6:   
   7:  this.breathes = "yes";
   8:   
   9:  }
  10:   
  11:  function Dog()
  12:   
  13:  {
  14:   
  15:  this.bark = "aaarf";
  16:   
  17:  }
  18:   
  19:  Dog.prototype = new Animal();
  20:   
  21:  var rover = new Dog();
  22:   
  23:  alert(rover.bark); // from Dog
  24:   
  25:  alert(rover.breathes); // from Animal
  26:   
  27:  </script>

The prototype chain for an object comes into play when reading a property of an object or calling a method of an object. When you read rover’s bark property, the value “aaarf” is returned. This is a property of the Dog object. When you read rover’s breathes property, the value “yes” is returned. Breathes is not a property of the Dog object. However, since an instance of the Animal object is assigned to the Dog constructor function’s prototype property, rover can breathe.

When first working with prototypes, I found it confusing that you don’t assign a prototype to an object itself. Instead, you associate a prototype with the constructor function for an object. This makes sense since you (typically) want the prototype to be associated with all instances of an object and not just one instance of an object.

However, if you want to modify a particular object’s prototype, then you can take advantage of the magic __proto__ property. For example, the following script does exactly the same thing as the previous script that used the Dog.prototype property:

   1:  <script type="text/javascript">
   2:   
   3:  function Animal()
   4:   
   5:  {
   6:   
   7:  this.breathes = "yes";
   8:   
   9:  }
  10:   
  11:  function Dog()
  12:   
  13:  {
  14:   
  15:  this.bark = "aaarf";
  16:   
  17:  }
  18:   
  19:  var rover = new Dog();
  20:   
  21:  rover.__proto__ = new Animal();
  22:   
  23:  alert(rover.bark); // from Dog
  24:   
  25:  alert(rover.breathes); // from Animal
  26:   
  27:  </script>

You might conclude, after examining the script above, that the __proto__ property is just a synonym for the constructor.prototype property. And, in many cases __proto__ is equal to constructor.prototype:

   1:  <script type="text/javascript">
   2:   
   3:  function Thing1() {}
   4:   
   5:  var a = new Thing1();
   6:   
   7:  alert( a.constructor.prototype === a.__proto__ ); // returns true
   8:   
   9:  </script>
  10:   

However, the two properties are not synonyms in several situations. First, the constructor.prototype property and __proto__ property can get out of sync. The value of constructor.prototype is copied to the __proto__ property when an object is created. Either (or both) the constructor.prototype property or the __proto__ property might change as the script continues to execute:

   1:  <script type="text/javascript">
   2:   
   3:  function Thing1() {}
   4:   
   5:  var a = new Thing1();
   6:   
   7:  alert( a.__proto__ === a.constructor.prototype); // returns true
   8:   
   9:  // Change Thing1's prototype chain
  10:   
  11:  function Thing2() {}
  12:   
  13:  Thing1.prototype = new Thing2();
  14:   
  15:  alert( a.__proto__ === a.constructor.prototype); // returns false
  16:   
  17:  </script>
  18:   

Furthermore, the constructor property for an object does not always return the name of the constructor function for an object. Unfortunately, if there is a prototype chain, the constructor property can return the name of a function higher in the prototype chain:

   1:  <script type="text/javascript">
   2:   
   3:  function Thing1() {}
   4:   
   5:  function Thing2() {}
   6:   
   7:  Thing1.prototype = new Thing2();
   8:   
   9:  var a = new Thing1();
  10:   
  11:  alert( a.constructor ); // returns Thing2
  12:   
  13:  </script>

I would expect the script above to display Thing1, but it displays Thing2. If the prototype chain reached higher, to Thing3, then a.constructor would return Thing3 (There is a discussion of this topic by Brendan Eich at https://mail.mozilla.org/pipermail/es4-discuss/2007-September/001155.html).

Using __parent__

The last magic property that I want to examine is named __parent__. Whereas the __proto__ property is useful for understanding the prototype chain and how properties get resolved, the __parent__ property is useful for understanding the scope chain and how variables get resolved.

Technically, all variables in JavaScript are properties of some object. A global variable is a property of the Global object (the Window object in a browser). For example, the following script works just fine:

   1:  <script type="text/javascript">
   2:   
   3:  var bob = "Hello!";
   4:   
   5:  alert( window.bob ) // displays Hello!
   6:   
   7:  </script>
   8:   

A local variable defined in a function becomes a property of the function’s Variable object. The function’s Variable object gets created when a function is interpreted (not when the function is executed).

Since variables are properties of objects (either the Global object or a function’s Variable object), functions determine variable scope. The value of a variable is resolved by walking up a function’s scope chain. First, the properties of the current function’s Variable object are checked. If the variable is not resolved, then the next function containing the current function is checked. The scope chain is walked up all the way to the Global object.

Consider the following script:

   1:  <script type="text/javascript">
   2:   
   3:  function getAdder()
   4:   
   5:  {
   6:   
   7:    var counter = 0;
   8:   
   9:    function adder()
  10:   
  11:    {
  12:   
  13:      return counter += 1;
  14:   
  15:    }
  16:   
  17:    return adder;
  18:   
  19:  }
  20:   
  21:  var adder = getAdder();
  22:   
  23:  alert( adder() ); // displays 1
  24:   
  25:  alert( adder() ); // displays 2
  26:   
  27:  </script>
  28:   

This script contains a function named getAdder() that returns an inner function named adder(). Consider how the value of counter is resolved when adder() is called. First, the Variable object associated with the inner adder() function is checked. Because counter is not a local variable for adder(), the next function in adder’s scope chain is checked. In this case, the Variable object for getAdder() is checked. The getAdder() function’s Variable object does, in fact, include a counter property.

The JavaScript language does not provide you with a method of accessing a function’s Variable object. The only way to access this object is by taking advantage of the __parent__ magic property. For example, the following script (which works in Firefox) returns the Global scope object:

   1:  <script type="text/javascript">
   2:   
   3:  function doSomething() {}
   4:   
   5:  alert(doSomething.__parent__); // returns Window
   6:   
   7:  </script>
   8:   

The Global scope object in the case of a browser is the Window object. All global variables become properties of the Window object.

Unfortunately, the __parent__ property does not work with nested functions when used with Firefox (SpiderMonkey). When __parent__ is used with Firefox, it always returns either the Window object or null. If you want to use __parent__ with nested functions, then you need to use Rhino.

Rhino is the Java version of the Mozilla JavaScript engine. You can download Rhino from http://developer.mozilla.org/en/docs/Rhino. To get Rhino to work in Windows, I had to follow the instructions from the following blog entry by Luke Maciak: http://www.terminally-incoherent.com/blog/2008/01/08/rhino-scripting-java-with-javascript.

After Rhino is setup, you can execute JavaScript statements from the command line. I executed the following commands:

   1:  function f() 
   2:   
   3:  {
   4:   
   5:    var bob='hello';
   6:   
   7:    var inner = function(){}; 
   8:   
   9:    var parent = inner.__parent__; 
  10:   
  11:    var contents = ''; 
  12:   
  13:    for (k in parent) contents += k + ' '; 
  14:   
  15:      print(contents); 
  16:   
  17:  }
  18:   
  19:  f();

The script above contains a function named f(). This function contains an inner function named inner. The __parent__ property of the inner function returns f’s Variable object. Therefore, when the script is executed, the following list of items is printed:

arguments bob contents parent inner

These are the properties that you would expect for the f function’s Variable object. The first items, represents the parameters passed to the f() function. The remaining items correspond to each of the f() function’s local variables.

1 Comment

  • Hi Bryan,

    Great question! In Firefox, the __proto__ magic property is read/write as demonstrated by the following script:

    var proto1 = {doSomething: function(){alert('boom')} };
    var proto2 = {doSomething: function(){alert('bang')} };

    var thing = {};

    // proto1
    thing.__proto__ = proto1;
    thing.doSomething(); // displays boom

    // proto2
    thing.__proto__ = proto2;
    thing.doSomething(); // displays bang

Comments have been disabled for this content.