JavaScript Lazy Inheritance

Alternative Lazy JavaScript Inheritance

Lazy Inheritance is an approach intended to simplify writing OOP and provides support of prototype-based classes hierarhies, automatic resolving and optimizing classes dependencies.

JSINER (originated from JavaScript INheritance supportER) is a lazy inheritance implementation in JavaScript. JSINER page on SoftAMIS

Overview

One of the most powerful features offered by object oriented programming (OOP) is inheritance (or ability to create subclasses of particular class). On the one hand, JavaScript does not involve full-fledged support of classes such as one offered by C++ or Java.
On the other hand, it supports constructors which are able to create objects with the use of executing code which allocates storage for the objects and initializes these objects (or part of them) by assigning initial values to their properties. There are several possible ways to implement inheritance in JavaScript which are widely known and used.  All of them have their own advantages and disadvantages. 

Lazy Inheritance design pattern

"Lazy inheritance" is a design pattern used in JavaScript computer programming. It designates a postponed linking of an object with it's prototype (class) until it is needed. If used properly, such approach may increase efficiency, simplicity and flexibility of OOP based code written using JavaScript. Unlike of "classical" approach, it supports a "Lazy" way of inheritance implementation, since reference to parent class is invoked only at the moment of object instance creation. Basically, it's possible to say that instances of objects in such approach are created in "mixed" mode – on first invocation, an appropriate factory is used to modify object constructor prototype which is later used for subsequent object instances creation. Moreover, since "Lazy inheritance" is called only once at the moment of first object instance creation, it becomes possible to combine process of class prototype creation with resolving necessary dependencies of that class. In other words, the process of prototype construction also allows loading scripts (if ones were not loaded before) which particular class depends on.

Such approach to inheritance support has the following benefits:

  •  "Lazy inheritance" has the same benefits as classical JavaScript prototype features;
  •  It is not necessary to maintain proper order of script files declaration;
  •  In most cases, HTML page is loaded faster since there are no objects created during page initialization and since some scripts could be loaded only at the moment in which they are actually necessary (they are necessary if the caller code during it's execution really creates instances of corresponding classes);
  • Dependencies are declared in more explicit way and class depends only on concrete scripts; Moreover, it's not necessary to artificially group particular scripts into "modules" and define dependencies between such "modules";
  •  If lazy mode of scripts loading is used, only necessary scripts (which are actually required for application functionality) will be loaded. If, for example, some HTML page may operate in different modes, like "read-write" and "read-only", for every mode required scripts will be loaded and this will be performed automatically without manual script loading optimization.

But before digging into details, let's consider existing approaches used to implement inheritance.

Classical prototype-based inheritance

JavaScript supports prototype-based inheritance. Each object constructor has a prototype property which is used to implement prototype-based inheritance and shared properties. Every object created by that constructor has an implicit reference to the prototype associated with its constructor. Such approach allows writing object oriented code in JavaScript.

The following fragment of code illustrates the common way to do this.
Let's assume that the following code is defined in person_cl.js JavaScript file and declares Person class:
    /**
     * Person’s constructor.
     */
    function Person(aName)
    {
      this.fName = aName;
    }
    /**
     * Here we define function which returns name of person and assign that function to
     * Person class prototype.
     */
    Person.prototype.getName = function()
    {
       return this.fName;
    };
    /**
     * Here we declare function toString() that returns string representation of
     * Person and assign that function to Person class prototype
     */
    Person.prototype.toString = function()
    {
       return "Person: " + this.getName();
    };

Let's declare another class, Employee which is inherited from Person one.
Let's assume that declaration of that class is placed to employee_cl.js JavaScript file:
    /**
     * Employee constructor
     */  
    function Employee(aName, aUID)
    {
      this.fName = aName;
      this.fUID = aUID;
    }
    /*   
     * The inheritance definition.
     * Here we create instance of Person and define that is inherited from Person,
     * specify constructor for Employee and add superClass property to Employee class
     */
    Employee.prototype = new Person();
    Employee.prototype.constructor = Employee;
    Employee.superClass = Person.prototype;
    /**
     * Here we declare function which returns UID of employee
     * and assing it to Employee class prototype
     */
    Employee.prototype.getUID = function()
    {
      return this.fUID;
    };
    /**
     * Here we redeclare definition of toString() function which should be used by
     * Employee class. Our declaration calls function from Person class and adds own Employee
     * related information
     */  
    Employee.prototype.toString = function()
    {
      var person = Employee.superClass.toString.call(this);
      return this.getUID() + ":" + person;
    };

And this is sample HTML page which uses declarations of JavaScript object above:
  <html>
    <head>
      <title>The Classical JavaScript inheritance test.</title>
      // Order of references to scripts is important for proper code execution.
      <script src="script/person_cl.js"></script>
      <script src="script/employee_cl.js"></script>
   </head>
   <body>
     <script>
       var employee = new Employee('John Doe', 1212);
       alert(employee);
     </script>
    </body>
  </html>

Everything is seems to be quite straightforward in these examples so far.
However, such a "classical" implementation of inheritance has several disadvantages:

  • Definition of object inheritance spreads over several declarations;
  • The result of the inheritance depends on actual inheritance declaration order (i.e. which code will be executed earlier), because declaring inheritance is ordinary JavaScript operation of assignment;
  • Classical inheritance requires creation of object instance for binding objects;
  • The JavaScript modules (script statements) declaration should be properly organized in HTML document. If amount of scripts which are to be used by particular HTML page is small, this does not look as serious issue, but if amount of included scripts is significant, such a limitation could be quite a serious issue which forces one to have correct answers for several difficult questions. For example, which order of script embedding should be used if the document requires 50 modules? How will cross-references and dependencies affect declaration order?

Prototypal approach

There is another way of creating several objects with the same structure in JavaScript offered by Douglas Crockford.
This approach assumes replacing prototype inheritance for prototypal using factory method instead of constructor.
Such a factory method is responsible for creation of new object instance.
Generally speaking, such approach does not represent pure inheritance, since it is oriented to creation JavaScript instances with the same properties, rather than classes.
However, it is intended to solve tasks which are close to ones solved by inheritance, and that's why we consider it there.

The following code snippet illustrates prototypal approach in more details.We declare the same example classes - Person and Employee. First, define Person using prototypal approach.
Let's assume that declaration of that class is placed to person_pp.js JavaScript file.
    /**
     * First, we define function which represents
     * a factory for creation of Person objects
     */
    function Person(aName)
    {
      var self =
PROTOTYPAL.object();
      self.fName = aName;
      self.toString = Person.toString;
      self.getName = Person.getName;
      return self;
    }
    /**
     * Here we declare function which will return name of Person and
     * adding it to Person object
     */
    Person.getName = function()
    {
       return this.fName;
    };
    /**
     * Here we declare function which returns representation of the Person object and
     * assign it to Person object
     */
    Person.toString = function()
    {
      return "Person: " + this.getName();
    };

Let's declare another class, Employee which is inherited from Person one.
Let's assume that declaration of that class is placed to employee_pp.js JavaScript file.
  /**
   * Here we define factory which will be used to
   * create Employee that extend Person
   */
  function Employee(aName, aUID)
  {
    // here we call method from library (prototypal.js)
    // which supports prototypal inheritance
    var self = PROTOTYPAL.object( Person(aName) );
    self.fUID = aUID;
    self.getUID = Employee.getUID;
    self.toString = Employee.toString;
    return self;
  }
  /**
   * Here we declare function which returns representation of the Employee object and
   * assign it to Employee object
   */
  Employee.toString = function()
  {
    return this.getUID() + ":" + this.getName();
  };
  /**
   * Here we declare function which will return UID of Employee and
   * adding it to Employee object
   */
  Employee.getUID = function()
  {
    return this.fUID;
  };

And this is sample HTML page which uses declarations of JavaScript object above:
  <html>
    <head>
      <title>The Prototypal JavaScript inheritance test.</title>
       // We also need to include base prototypal related code
       <script src="script/prototypal.js"></script>
       // Order of references to scripts is important for proper code execution.
       <script src="script/person_pp.js"></script>
       <script src="script/employee_pp.js"></script>
     </head>
    <body>
     <script>
        var employee = new Employee('John Doe', 1212);
        alert(employee);
      </script>
    </body>
  </html>

Comparing to "classical" inheritance, the prototypal based approach has significant advantages,
but also several significant drawbacks:

  • As soon as object instance is created, and later it's necessary to alter its structure (i.e. set of properties and methods) this could be done online on individual object level. In other words, any changes which could be performed with object prototype does not affect objects crated on that prototype at all.Contrary, if “classical inheritance” is used for altering structures of ALL created instances, it is simply enough to change corresponding prototype.Actually, for some types of application this can be unnecessary or inapplicable; however, it is extremely useful for some other types of applications to have such functionality because it allows implementing basic (or framework) logic without worrying about how it will be adapted for particular application.Support of classical inheritance is extremely important if class is created using aggregation (i.e. class has properties which are classes too) and it’s necessary to change structure not only for that class, but also structure of classes which are aggregated by that class.
  • Another drawback of prototypal approach – all objects returned by factory are untyped, and it's less convenient to work with them comparing to typed objects;
  • And finally, prototypal approach requires that parent should be already created before definition of child object (in other words, referring to example above, at the moment of Employee object definition, the JavaScript runtime should be able to create instance of Person).
  • The same as for "classical inheritance", it is required to maintain proper order of script files declaration to have the entire inheritance scheme working.

JSINER' Lazy Inheritance

JSINER (originated from JavaScript INheritance supportER) represents a JavaScript library intended to simplify writing object oriented code in JavaScript as well as managing external scripts dependencies.

JSINER’ offers approach which simplifies writing object oriented code with support of prototype based inheritance.
Unlike of "classical" approach, it represents a "Lazy inheritance" because reference to parent class is invoked only at the moment of object instance creation.
Basically, it's possible to say that instances of objects in such approach are created in "mixed" mode – on first invocation, an appropriate factory is used to modify object constructor prototype which is later used for subsequent object instances creation.
Moreover, since "Lazy inheritance" is called only once at the moment of first object instance creation, it becomes possible to combine process of class prototype creation with resolving necessary dependencies of that class. In other words, the process of prototype construction also allows loading scripts (if ones were not loaded before) which particular class depends on.

Such approach to inheritance support has the following benefits:

  1. "Lazy inheritance" has the same benefits as classical JavaScript prototype features;
  2. It is not necessary to maintain proper order of script files declaration (contrary to "classical inheritance");
  3. In most cases, HTML page which contains JavaScript based on JSINER is loaded faster since there are no objects created during page initialization (contrary to prototypal and classical approach) and since some scripts could be loaded only at the moment in which they are actually necessary (they are necessary if the caller code during it's execution really creates instances of corresponding classes);
  4. Dependencies are declared in more explicit way and class depends only on concrete scripts; Moreover, it's not necessary to artificially group particular scripts into "modules" and define dependencies between such "modules";
  5. If lazy mode of scripts loading is used, only necessary scripts (which are actually required for application functionality) will be loaded. If, for example, some HTML page may operate in different modes, like "read-write" and "read-only", for every mode required scripts will be loaded and this will be performed automatically without manual script loading optimization.

The following code snippets illustrate JSINER "Lazy inheritance" approach in more details.
Again, we declare the same example classes - Person and Employee.

First, we define Person.
Let's assume that declaration of that class is placed to person.js JavaScript file.
   /**
    * Constructor for Person class
    */
   function Person(aName)
   {
     this.fName = aName;
   }
   /**
    * Function which returns name of Person’s.
    * That function is assigned to prototype of Person class corresponding by "classical" inheritance.
    */
   Person.prototype.getName = function()
   {
     return this.fName;
   };
   /**
    * Here we define function which returns string representation of Person
    * assign it to prototype of Person class
    */
   Person.prototype.toString = function()
   {
     return "Person: " + this.getName();
   };

Now we illustrate how Person may be extended using couple of examples.

Example 1 - "inheritance only".

This example is quite basic and illustrates only the way how "pure inheritance"
should be supported via JSINER (without resolving dependencies between classes and required script files).
Here we assume that the code below is placed to employee1.js file.

   /**
    * Here we define constructor for Employee class and declare that Employee class
    * inherits Person one
    */
  function Employee(aName, aUID)
  {
    // lazy inheritance calling
    var self = JSINER.extend(this, "Person");
    self.fName = aName;
    self.fUID = aUID;
    return self;
  }
  /**
   * Here we define function which return UID of employee and assign it to
   * prototype of Employee class.
   * This is exact approach as one used by "classical" inheritance
   */
  Employee.prototype.getUID = function()
  {
    return this.fUID;
  };
  /**
   * Here we define function which returns string representation of
   * Employee object and assign it to Employee class prototype (as if classical approach is used).
   * Our implementation combines/ string representation of Person object
   * and own data from Employee class
   */
  Employee.prototype.toString = function()
  {
     var person = Employee.superClass.toString.call(this);
     return this.getUID() + ":" + person;
  };

And this is sample HTML page which uses declarations of JavaScript object above:

  <html>
    <head>
      <title>The JavaScript Lazy inheritance test.</title>
      // We need to include reference to JSNIER code
      <script src="script/jsiner.js"></script>
      // Now it's not necessary to maintain order of scripts loading manually.
     <script src="script/employee1.js"></script>
     <script src="script/person.js"></script>
   </head>
   <body>
     <script language="JavaScript1.2">
        var employee = new Employee('John Doe', 1212);
        alert(employee);
      </script>
   </body>
 </html>

During execution of example of code listed above, lazy inheritance is called only once for f
irst creation of Employee instance.
It is not necessary to keep proper order of script files declaration in HTML document.

 Example 2 - "inheritance and resolving references"

This example illustrates more advanced features of JSINER libarary, such as automatic resolving of references to particular JavaScript files in which appropriate JavaScript classes are defined.

Here we assume that the code below is placed to employee2.js file.

  /* Here we inform JSINER that Employee class depends on person script.
   * Actually, the "person" string does not represent a script name, but
   * rather some key which is associated with actual script.
   * JSINER allows specifying/ mapping functionality which is responsible
   * to determine actual name of script using given key.
   * However, for simplicity of examples, here it’s assumed that resolver considers
   * key of script as name of script file.
   */
  JSINER.addDependency( {Employee:"person"} );
  /**
   * Exactly as in example 1, we define constructor for Employee class.
   * In general, all code below is the same as one used in Example 1
   */
  function Employee(aName, aUID)
  {
    var self = JSINER.extend(this, "Person"); 
    self.fName = aName;
    self.fUID = aUID;
    return self;
  }
  /**
   * Here we define function which return UID of employee and assign it to
   * prototype of Employee class.
   * This is exact approach as one used by "classical" inheritance
   */   
  Employee.prototype.getUID = function()
  {
    return this.fUID;
  };
 /**
   * Here we define function which returns string representation of Employee
   */
  Employee.prototype.toString = function()
  {
     var person = Employee.superClass.toString.call(this);
     return this.getUID() + ":" + person;
  };

This is sample HTML page which uses declarations of JavaScript object for Example 2:
  <html>
    <head>
      <title>The JavaScript Lazy inheritance test.</title>
       // We need to include reference to JSNIER code
      <script src="script/jsiner.js"></script>
      // Note that we include reference to script that contains Employee class only
      <script src="script/employee2.js"></script>
      // And no it's not required to reference person.js script explicitely -
      // JSINER will resolve and load it automatically
      <!--<script src="script/person.js"></script>-->
   </head>
   <body>
     <script language="JavaScript1.2">
        var employee = new Employee('John Doe', 1212);
        alert(employee);
      </script>
   </body>
 </html>

During execution of example code listed above, linkage of Employee and Person as well as
loading of necessary script "person.js" is performed automatically with the first creation of Employee instance.

As it is illustrated by examples above, proposed "Lazy inheritance" pattern is similar
to Prototypal approach, but:

  • It is called only once during first creation of object instance;
  • Linkage of objects and scripts is performed automatically;
  • To link classes the prototype based inheritance is used;

In general, the proposed scheme considers "lazy" loading as primary mode for loading particular scripts.
However, this is not strict requirement – it is also possible to force loading of all scripts which form particular application before starting objects creation if this way of loading is required by particular application architecture.

Since "lazy" inheritance approach is non-intrusive, it could be used in combination with other inheritance pattern.
However, it is necessary to remember that simultaneous use of several types of inheritance
within the same project or application can be very confusing and non-convenient for development, support and maintenance.

JSINER’ Inheritance Internals

Here hightlight some details of inheritance and dependencies resolving in JSINER library.
"Lazy inheritance" is invoked within the Object' constructor code and is called only once for first object instance creation.

After invocation, the following steps are performed by JSINER library:

  • First, the algorithm tests Object' dependencies;
  • If Object' dependency had been registered before the object constructor was called (interrelations can be defined in the object constructor too), corresponding JavaScript dependencies are loaded.
  • Then, if the class, from which the object inherits, is defined and it is not a default one (Object), Object's constructor prototype is modified by classical schema of prototype-based inheritance.
  • After completing prototype modification, constructor of the Object' is called again to apply changes to new instance of the Object.

There steps are illustrated by diagram:

JSINER' Lazy Inheritance diagramm

The derived instance of the Object may be modified in the constructor according to particular logic.
For example, some properties of the object may be defined.

The resulting object is the same JavaScript object as it would be created with classical prototype-based inheritance.

Conclusion

As the matter of thumb, there is no "silver bullet" solution and proposed approach does not pretend to be universal way of implementing inheritance in JavaScript.
Of course, choice of inheritance type declaration is dictated by particular needs and specifics of particular application.
However, the approach described there has several significant advantages that allow simplifying of writing object oriented code in JavaScript.

Where it works

Proposed JSINER' Lazy inheritance approach was tested under
* Windows Internet Explorer 6.0/7.0
* Mozilla Firefox 1.5/2.0
* Opera 9.10
* MAC Safari 2.03
* MAC Firefox 1.5.0.11
* MAC Opera 9.0

Lazy Inheritance Implementation

Useful links

If you'd like to find more information related to support of OOP and inheritance in JavaScript, please refer to the following resources:

One of Java's many applications in wireless phone is a mail application. Where client uses simple mail protocol (SMTP) to send messages over the network. Java is sparingly used in hosting solutions that are offering dedicated hosting besides other hosting plans. Because more competencies are required to offer java based hosting it is available with very few hosting providers.Java based banner ads are used to show sequences of images that can be linked to separate websites. New technologies are rapidly changing the way computer software is created. Java runtime environment is common in computers these days, which is required by many pc applications. Java can also be used seamlessly with Yahoo’s search marketing API.

Comments

thanks for cool article :)

Free open-source implementation and work examples can be downloaded from
http://downloads.sourceforge.net/jsiner/jsiner0.97.zip?modtime=117716922...

dedicated server hosting
Advertise on this site

Recent Comments