javascript achieve class like code with closure, prototype and etc...

8007 ワード

Javascript is featured of something that is special among other object oriented or object based language, where you do not have class, and there is some mechanism which is called the prototype inheritance that can help you achieve something that fimiliar with most OO programmer. 
 
With object inheritance, it is quite possilbe to simulate the class like code with the use of closures and prototype inheritance.
 
let's first see an example of what will become after we have the class like code implemented.
 
var Person = Object.subClass({

  init: function(isDancing) { 
    this.dancing = isDancing;
  },
  dance : function() {
    return this.dancing
  }
});



var Ninja = Person.subClass({
 init : function() { 

   this._super(false);
 },
 dacne : function() {
   // call hte inherited version of the dance() 
   return this._super();
 },
 swingSword: function() {
   return true; 
 }
});

var n = new Ninja();

assert(n.swingSword(), "Get true, as we expected");
assert(!n.dance(), "The inverse of the super method's value - false.");

// Should all be true 
assert(p instanceof Person && n instance Ninja && n instanceof Person, "the objects inherit functionalities from the correct sources.");

 
 
 
and below is the code that has the library implementation.
 
/**************************************
*@Summary
* With the help of object singleton inheritance, we achieve something that we are faimiliar with in some strong typed language
*
*  this utilize this feature to extend the element in the HTML
*
* @Usage:
*   

var Person = Object.subClass({

  init: function(isDancing) { 
    this.dancing = isDancing;
  },
  dance : function() {
    return this.dancing
  }
});



var Ninja = Person.subClass({
 init : function() { 

   this._super(false);
 },
 dacne : function() {
   // call hte inherited version of the dance() 
   return this._super();
 },
 swingSword: function() {
   return true; 
 }
});

var n = new Ninja();

assert(n.swingSword(), "Get true, as we expected");
assert(!n.dance(), "The inverse of the super method's value - false.");

// Should all be true 
assert(p instanceof Person && n instance Ninja && n instanceof Person, "the objects inherit functionalities from the correct sources.");

* @TODO:
* test it 
***************************************/

/**
*@Comment: class like instance
*   point 1: this is to test the browser compatability. since ew need to test if function can be serialized, if a functin can be serialized, the n
    it is possible to test if the function has used _super

*/

(function () {
  var initializing = false,
  // determine if functions can be serialized 
  // Comment point 1
  fnTest = /xyz/.test(function () { xyz; }) ? /\b_super\b/ : /.*/;
  
  Object.subClass = function (prop) {
    var _super = this.prototype;

    // Initialize a base class (but only create the instantiate,
    // don't run the init constructor
    initializing = true;
    // so given the code sample 
    // var Ninja = Person.subClass(...)
    // this will correspond to the object of 'Person'
    var proto = new this();
    initializing = false;


    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // check if we 're overwriting an existing function
      proto[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ?
      (function (name, fn) {
        return function () {
          var tmp = this._super;

          // add a new ._super() method that is the same but on the super-class
          this._super = _super[name];

          // the method only need to be bound temporarily, so we remove it when we're done execting 
          var ret = fn.apply(this, arguments);
          this._super = tmp;

          return ret;


        };

      })(name, prop[name]) :
      prop[name];
    }

    // we create a dummy class that can both act as the constructor as well as the class type as well
    function Class() {
      // All construction is actually done in the init method
      if (!initializing && this.init) {
        this.init.apply(this, arguments);
      }
    }

    // populate our constructed prototype objet 
    Class.prototype = proto;

    // Enforce the constructor to be what we expect 
    Class.constructor = Class;


    // and make it extensible so that we can do things like 
    // var Person = Object.subClass(...)
    // var Ninja = Person.subClass(...)
    // and that is because the first Object.subClass() will return Class, and we want to allow user to call
    // subClass further on this function object
    // you need this because it the function's prototype is not directly the Object itself?
    Class.subClass = arguments.callee;

    return Class;
  };
})();
  
 
 
 
and below is the code that we used to test the function. 
 
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="classlike.js" type="text/javascript"></script>
    <script src="../unit.js" type="text/javascript"></script>
    <script type="text/javascript">
      window.onload = function () {

        test("classlike test", function () { 

          var Person = Object.subClass({
          init: function(isDancing) { 
            this.dancing = isDancing;
          },
          dance: function() {
            return this.dancing
          }
          });

        var Ninja = Person.subClass({
         init : function() { 

           this._super(false);
         },
         dacne : function() {
           // call hte inherited version of the dance() 
           return this._super();
         },
         swingSword: function() {
          return true;
         }
        });

        var n = new Ninja();

        assert(n.swingSword(), "Get true, as we expected");
        assert(!n.dance(), "The inverse of the super method's value - false.");

        // Should all be true 
        assert(p instanceof Person && n instanceof Ninja && n instanceof Person, "the objects inherit functionalities from the correct sources.");
      }
   );
        
};
    </script>
    <style type="text/css">
      #results li.pass { color: Green }
      #results li.fail { color: Red }
    </style>
</head>
<body>
<ul id="results" />
</body>
</html>