Differential inheritance in JavaScript: Difference between revisions

From MozillaZine Knowledge Base
Jump to navigationJump to search
m (remove from deleted cat)
(moved to devmo)
 
(One intermediate revision by the same user not shown)
Line 1: Line 1:
Netscape 4.x and Mozilla both provide access to the internal prototype information associated with an Object in JavaScript using the <code>__proto__</code> property. By manipulating this property, a developer can emulate "differential inheritance", a common technique in prototype-oriented programming models.
See [http://developer.mozilla.org/en/docs/Differential_inheritance_in_JavaScript Differential inheritance in JavaScript] at [http://developer.mozilla.org MDC].


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.
[[Category:Redirects]]
 
<pre>
Object.prototype.clone = function(){
  var newObject = new this.constructor();
  newObject.__proto__ = this;
  return newObject;
};
 
Root = new Object();
</pre>
 
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.
 
<pre>
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() );
</pre>
 
===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 <code>Object</code> 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 (<code>Object</code> 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:Example code]] [[Category:JavaScript example code]]

Latest revision as of 18:13, 24 May 2007