JavaScript模拟Java类继承

jopen 10年前

    javascript采用原型继承的方式继承一个类,但一些使用过Java的程序员可能习惯使用经典的类继承,但javascript原生并不支持这种方式,因此需要手动实现。我是通过定义一个定义类的函数实现的,由于javascript没有访问修饰符,因此如果需要使用到private成员,请使用闭包。

/*将一个对象的自有属性复制到另一个对象的方法*/          function merge(from, to){              for(var i in from){                  if(from.hasOwnProperty(i)){                      to[i] = from[i];                  }              }          }            /*用于定义一个类           *参数:构造函数,继承的父类, 属性, 静态属性, 是否为单例模式           *注意:单例模式下返回非原始构造函数           */          function defineClass(constructor, parent, properties, statics, isSingleton){              /*如果为单例模式,保存实例,并在以后的调用中返回此实例*/              if(isSingleton){                  var instance, oldConstructor = constructor;                  constructor = function(){                      if(instance) return instance;                      oldConstructor.apply(this, arguments);                      instance = this;                  }              }             /*设置原型属性,这意味着传入的构造函数的原型属性将被覆盖              *javascript没有函数重载,因此parent函数需要做一些特殊处理,详情见parent定义              */              constructor.prototype = new parent();             /*将自有属性复制到原型中              *将静态属性复制到构造函数中,这意味着将不会继承parent的静态属性              */              merge(properties, constructor.prototype);              merge(statics, constructor);             /*将构造函数更改为当前构造函数              *将parent的引用保留              */              constructor.prototype.constructor = constructor;              constructor.prototype.parent = parent;              return constructor;          }            function parent(){             /*可以将这里看成两个构造函数,一个在定义子类时使用的无参构造函数,一个有参构造函数              *如果子类需要参数来使用父类初始化,可以通过this.parent得到              */              this.name = "parent";              if(arguments.length){                  log(this.name + "'s constructor with params");              }          }            var child = defineClass(function(){              //this.parent.apply(this, arguments);              this.name = "child";              if(arguments.length){                  log(this.name + "'s constructor with params");              }          }, parent, {              say: function(){                  log(this.name);              }          }, {              value: "static"          }, true);            var instance = new child(), instance2 = new child();            log(child.value);                           //static          log(instance.name);                        //child          instance.say();                             //child          log(instance === instance2);              //true          log(instance instanceof parent)           //true           /*可以在child基础上扩展          */            var grandSon = defineClass(function(name){              this.name = "grandSon";              if(arguments.length){                  log(this.name + "'s constructor with params");              }          }, child, {              shout: function(){                  log("shout: " + this.name);              }          });            var instance3 = new grandSon();            instance3.say();                           //grandSon          instance3.shout();                         //shout: grandSon            log(instance3 instanceof child);        //true          log(instance3 instanceof parent);        //true            /*打印日志*/          function log(msg){              if(window.console){                  console.log(msg);              }          }