Differential inheritance in JavaScript: Difference between revisions

From MozillaZine Knowledge Base
Jump to navigationJump to search
m (format)
Line 45: Line 45:
</pre>
</pre>


A word of caution: Internet Explorer currently does not support the <code>__proto__</code> property.  It is recommended that this technique be reserved for situations where the developer can be certain that the script will be executed by Mozilla or other interpreters that support the <code>__proto__</code> property, like Safari and KJS.
===Words of caution===
 
Internet Explorer currently does not support the <code>__proto__</code> property.  It is recommended that this technique be reserved for situations where the developer can be certain that the script will be executed by Mozilla or other interpreters that support the <code>__proto__</code> property, like Safari and KJS.
 
Also note that when you change the Object prototype, <i>all</i> javascript objects are affected. While this is what you wanted, there is a gotcha when it comes to object property enumeration -- the <code>for( variable in object )</code> iterator will also see your inherited function, and any code using the basic object as an associative array and iterating it like this without safeguarding from inherited properties (Object has no inherited enumerable properties by default) will most likely break. If your code lives in a vacuum where it will never affect code invented elsewhere and you still want to use both of these techniques, you can rewrite this iteration to avoid inherited properties using the <code>__proto__</code> property mentioned in the first gotcha above:
 
<pre>
for( variable in object )
  if( object.__proto__[variable] !== object[variable] )
  { /* your loop body here instead */ }
</pre>


[[Category:Javascript]] [[Category:Example code]] [[Category:Javascript example code]]
[[Category:Javascript]] [[Category:Example code]] [[Category:Javascript example code]]

Revision as of 13:08, 6 March 2005

Differential inheritance in Javascript

Netscape 4.x and Mozilla both provide access to the internal prototype information associated with an Object in Javascript using the __proto__ property. By manipulating this property, a developer can emulate "differential inheritance", a common technique in prototype-oriented programming models.

Differential Inheritance is a common prototype-oriented model that uses the concept that most objects are derived from other, more generic objects, and only differ in a few small aspects. Each object maintains a reference to its prototype and a table of properties that are different. The following code provides a simple method for "cloning" an object and a fundamental object, since the global variable Object actually refers to the Object constructor, not an actual Object.

Object.prototype.clone = function(){
  var newObject = new this.constructor();
  newObject.__proto__ = this;
  return newObject;
};

Root = new Object();

Using "clone", it becomes possible to simply derive more specific objects from a generic prototype. The following is a simple example of building up increasingly more specific objects using the clone method and differential inheritance.

Record = Root.clone();
Record.toString = function(){ return "a Record"; };
 
Person = Root.clone();
Person.firstName = false;
Person.lastName = false;
Person.toString = function(){ 
    if( this.firstName ){
      if( this.lastName ){
        return this.firstName + " " +this.lastName; 
      }else{
        return this.firstName;
      }
    }else{
      if( this.lastName ){
        return this.lastName;
      }else{
        return "a Person";
    }
  }
}
 
JoePerson = Person.clone();
JoePerson.firstName = "Joe";
alert( JoePerson.toString() );

Words of caution

Internet Explorer currently does not support the __proto__ property. It is recommended that this technique be reserved for situations where the developer can be certain that the script will be executed by Mozilla or other interpreters that support the __proto__ property, like Safari and KJS.

Also note that when you change the Object prototype, all javascript objects are affected. While this is what you wanted, there is a gotcha when it comes to object property enumeration -- the for( variable in object ) iterator will also see your inherited function, and any code using the basic object as an associative array and iterating it like this without safeguarding from inherited properties (Object has no inherited enumerable properties by default) will most likely break. If your code lives in a vacuum where it will never affect code invented elsewhere and you still want to use both of these techniques, you can rewrite this iteration to avoid inherited properties using the __proto__ property mentioned in the first gotcha above:

for( variable in object )
  if( object.__proto__[variable] !== object[variable] )
  { /* your loop body here instead */ }