JavaScript框架设计
上QQ阅读APP看书,第一时间看更新

5.2.2 JS.Class

项目地址:http://code.google.com/p/jsclassextend/

从它的设计来看,它是师承Dean Edwards的Base2,相似的类工厂实现还有mootools,第5.2.3小节的 simple-inheritance。它是通过父类构造器的extend方法来产生自己的子类,里面存在一个开关,防止在生成类时无意执行construct方法。

如Base2的base2.__prototyping,mootools的klass.$prototyping。它创建子类时,也不通过中间的函数来断开双方的原型链,而是使用父类的实例来做子类的原型,这点实现得非常精巧。

源码解读如下。

      var JS = {
          VERSION: '2.2.1'
      };
      JS.Class = function(classDefinition) {
          //返回目标类的真正构造器
          function getClassBase() {
              return function() {
                  //它在里面执行用户传入的构造器construct
                  //preventJSBaseConstructorCall是为了防止在createClassDefinition辅助方法中执行父
                  //类的construct
                  if (typeof this['construct'] === 'function' && preventJSBaseConstructorCall ===
      false) {
                      this.construct.apply(this, arguments);
                  }
              };
          }
          //为目标类添加类成员与原型成员
          function createClassDefinition(classDefinition) {
              //此对象用于保存父类的同名方法
              var parent = this.prototype["parent"] || (this.prototype["parent"] = {});
              for (var prop in classDefinition) {
                  if (prop === 'statics') {
                      for (var sprop in classDefinition.statics) {
                          this[sprop] = classDefinition.statics[sprop];
                      }
                  } else {
          //为目标类添加原型成员,如果是函数,那么检测它还没有同名的超类方法,如果有
                      if (typeof this.prototype[prop] === 'function') {
                          var parentMethod = this.prototype[prop];
                          parent[prop] = parentMethod;
                      }
                      this.prototype[prop] = classDefinition[prop];
                  }
              }
          }
          var preventJSBaseConstructorCall = true;
          var Base = getClassBase();
          preventJSBaseConstructorCall = false;
          createClassDefinition.call(Base, classDefinition);
          //用于创建当前类的子类
          Base.extend = function(classDefinition) {
              preventJSBaseConstructorCall = true;
              var SonClass = getClassBase();
              SonClass.prototype = new this();//将一个父类的实例当作子类的原型
              preventJSBaseConstructorCall = false;
              createClassDefinition.call(SonClass, classDefinition);
              SonClass.extend = this.extend;
              return SonClass;
          };
          return Base;
      };

创建一个Animal类与一个Dog子类。

      var Animal = JS.Class({
        construct: function(name) {
          this.name = name;
        },
        shout: function(s) {
          console.log(s);
        }
      });
      var animal = new Animal();
      animal.shout('animal'); // animal
      var Dog = Animal.extend({
        construct: function(name, age) {
          //调用父类构造器
          this.parent.construct.apply(this, arguments);
          this.age = age;
        },
        run: function(s) {
          console.log(s);
        }
      });
      var dog = new Dog("dog", 4);
      console.log(dog.name);
      dog.shout("dog"); // dog
      dog.run("run"); // run

演示静态成员的实现如下。

      var Shepherd = Dog.extend({
        statics: { //静态成员
          TYPE: "Shepherd"
        },
        run: function() { //方法链,调用超类同名方法
          this.parent.run.call(this, "fast");
        }
      });
      console.log(Shepherd.TYPE); //Shepherd
      var shepherd = new Shepherd("shepherd", 5);
      shepherd.run(); //fast

JS.Class虽然功能稍微薄弱些,但简洁得惊人。我们可以在它的基础上学习 Base2,mootools的实现。