• javascript框架之继承机制2


    我们来模仿一下最OO的mootools的继承机制。它的类都有一个叫做initialize构造方法,这与Java的类都有一个与类名同名的构造方法一样的道理。只不过,这些叫initialize或init都是借鉴自Prototype,而Prototype那帮人是Ruby出身。为了区别mootools那种污染原生方法的做法,我把类的构造器命名为variant,并且禁止查看构造方法(像浏览器禁止查看原生对象的构造方法那样)。

        var variant = function (options){
          options = options || {};
          var initialize = options.initialize || function(){};
          var klass = initialize ;
          klass.constructor = arguments.callee;
          klass.prototype.constructor = klass;
          klass.toString = function(){//禁止查看构造方法
            return "function variant(){\n    [variant code]\n}"
          }
          return klass;
        };
    

    这是一个非常简单的工厂方法,用于生产类的。options就是一属性包,可能装有我们的类的构造方法,我们要做的是把它提取出来,然后输送出去。

         function factory(a){
             a.b = b;
             a.c = c;
             return a;
          }
    

    不过,这就有点像倒爷,我们应该像水果商,从果农收购水果回来包装一番,才卖出去。这包装就是往要生成的类添加各种原型方法与类方法。我们进一步打造我们的类工厂,让生产的类拥有继承能力,也就是把第一部分的makeBridge 加上去。

    prototype继承是通过把子类的原型设置成父类的一个实例来进行继承的。因此无论是inherit也好,mixin也好,都是往子类的原型添加东西。打个比方,继承就是把一大堆属性与方法直接加在子类的原型上,mixin则相当于把一打属性与方法逐一加到构造函数的原型。不过在上面Tiger类的构造器写得有点不好,因为name属性本来父类就有,子类就不用定义一次。如果父类有许多实例属性,岂不是要写一大打赋值语句。应该改为

        var Tiger = variant({
          inherit:Animal,
          initialize:function(name,age){
            this.superclass(arguments);//this.name = name
            this.age =age;
          },
          getAge : function(){
            return this.age;
          },
          setAge : function(age){
            this.age = age;
          }
        })
    

    但是这种做法在第三代子类就行不通了,比如我们弄个子类叫IndiaTiger,它比Tiger多出一个类例属性location。

    var IndiaTiger = variant({
            inherit:Tiger,
            initialize:function(name,age,location){
              this.superclass(arguments);
              this.location =location;
            }
          });
    

    当new印度虎实例时就报错了,除非其父类的构造器没有用到this.superclass(arguments)。不用说,问题是出自this,它的不确定性总是为我们惹很多麻烦。这里的this总为IndiaTiger 的实例,因此this.superclass总为Tiger ,也因此我们无法实例化Animal 。javascript的实例化过程是,有父类先实例化父类,然后再到下级子类。由于我们无法通过klass.prototype.superclass获取Animal,我们可以用klass.superclass来试一下。klass为类,而this为实例:

    IndiaTiger.superclass.apply(this, arguments);
    //this为IndiaTiger 的实例
    //arguments为IndiaTiger 构造器的参数对象
    

    但我们不能把前面的IndiaTiger 写死,因为创建IndiaTiger 这个类时,它还不知自己叫IndiaTiger ,我们可以通过arguments.callee获取IndiaTiger自身。Tiger的构造相仿。

            var IndiaTiger = variant({
              inherit:Tiger,
              initialize:function(name,age,location){
                arguments.callee.superclass.apply(this, arguments);
                this.location =location;
              }
            });
    

    我们可以把它再抽取出来,这样每次就不用写这么长的代码了。

            function _super(o, args) {//o为子类的实例,agrs为子类构造的arguments对象
                return args.callee.superclass.apply(o, args);
            }
    

    上面的代码已经假设了,它的构造器总会有inherit这个属性,但如果没有岂不是会报错,另,它还假设了我们的类上面有一个属性叫superclass,因此我们要在类工厂中做相应的调整。添加或修改如下两行代码:

      var superclass = options.inherit || Object;
      klass.superclass = superclass; //类的superclass
    

    不过每次设置新类的构造器时都要添加一行_super(this,arguments)也太麻烦了,最好把它隐藏起来,内部调用。另,把_super方法放到工厂外,显得太松散,既然也是用来构建类,因此也该把它整合到类工厂中。

          function factory(a){
             var b = function(){
                 s();
                 a();
                 //*****其他方法
             }
             return b
          }
    

    也就是说,我们只要这样设置类的构造器即可:

            var IndiaTiger = Variant({
              inherit:Tiger,
              initialize:function(name,age,location){
                this.location =location;//★★★★★
              }
            });
    

  • 相关阅读:
    汉语-词语:办法
    汉语-词语:做法
    汉语-词语:说法
    汉语-词语:看法
    汉语-词语:想法
    汉语-词语:音色
    汉语-词语:声纹
    职业:斜杆青年
    汉语-流行词汇:傻白甜
    汉语-词语:慧根(生理学概念)
  • 原文地址:https://www.cnblogs.com/rubylouvre/p/1597174.html
Copyright © 2020-2023  润新知