解读rightjs的继承机制 1

继承机制的出现,说明javascript已经到达大规模开发的门槛了。像java,为了应该其工业化,把设计模式发挥到臻美!有什么东西能逼使javascript的代码达到几千甚至上万行呢?除了框架类库都辅助工具外,那就是游戏这种奢侈的娱乐。光显示界面,操作界面,评估系统也能细分。另一个像EXT的那样利用纯javascript取代HTML与CSS的功能来开发网页,这也是很庞大的东西。庞大的东西就要模块化,虽然每一个模块未必都是一种类,但类是其不可或缺的组成元素。由于javascript的目的就是实现网页的交互,因此这些类大部分包含着操作DOM元素的内容,如生成一个节点啦,把它插入到DOM树的某处啦,设置它的样式,为它绑定事件,删除它……凡此种种。许多操作如果作为类的方法而存在,把它们命名更好的名字会更合适些。在各个类的联动方面,著名的观察者模式比浏览器提供的事件机制更具吸引力,起码在模块的解耦方面更胜一筹,如下面代码涉及三个模块:

        this.keyboard
        .onLayoutChange(this.progress.setLayout.bind(this.progress))
        .onKeyPress(this.field.keyPressed.bind(this.field));

当键盘的外观发生改变后,上面的进度条也随之发生改变,当它的某个键被按下,显示区也相应发生响应。在暗地里,最后一个操作还会激发另一个操作:

keyPressed: function(key_code) {
    var element = this.pullElement(key_code);
    
    if (element) {
      element.droppinFx.cancel();
      element.highlight('#AFA', {
        duration: 160, onFinish: element.remove.bind(element)
      });
      
      this.fire('hit', element.innerHTML);//★★★★
    }
  },

而用jQuery来模拟实际上很难实现:

    this.settings.layouts.change(function(){
        var layout = $(this).val();
        var keynames = ths.keyboard.setLayout(layout);
        ths.progress.setLayout(keynames)
    });

第二个onKeyPress不是一个真正存在的事件,它是通过其他事件回调实现的。

  hightlightKey: function(event) {
    var key = this.keys[event.charCode] || this.keys[event.keyCode];
    if(key){
      if (!event.altKey && !event.ctrlKey && !event.metaKey) {
        event.stop();
        key.highlight({duration: 160});
        this.fire('key_press', event.charCode || event.keyCode);//这里是onKeyPress
      }
    }
 },

但这里的this并不是一个元素节点,事件机制对此无能为力,必需要引入观察者模式。如果真的需要这样设计,我们就要求类的存在了,至少在观察者模式中就要求有发布者对象与订阅者对象。mootools之所以能崛起,因为它提供了强大的继承机制,从而实现更复杂的编程。像EXT那样复杂的东西就更不在话下了。rightjs虽然不如上面提到的框架类库出名,但后生可畏,想必其作者也一定吸收了它们的优点。它的继承机制远远比它的前辈复杂强大,这正是我要学习它的原因。

var Class = function() {
  //处理参数,一般有两个参数,第一个是父类,第二个是对象属性包
  var args = $A(arguments), properties = args.pop() || {}, parent = args.pop();

  // basic class object definition
  //定义子类
  function klass() {
    return this.initialize ? this.initialize.apply(this, arguments) : this;
  };

  // 如果只指定了父类
  if (!args.length && !isHash(properties)) {
    parent = properties; properties = {};
  }

  // 为子类添加一些类方法,并继承父类
  $ext(klass, Class.Methods).inherit(parent);

  // catching the injections
  //特殊处理属性包的extend、include方法
  $w('extend include').each(function(name) {
    if (properties[name]) {
      var modules = properties[name];
      klass[name].apply(klass, isArray(modules) ? modules : [modules]);
      delete(properties[name]);
    }
  });
  //混入属性包的其他方法或属性
  return klass.include(properties);
};

样子长得同Prototypejs差不多,没办法,英雄所见略同,大家都爱拿Alex Arnell的实现来改良。里面有一个$ext方法:


//就是Prototype的extend,多了第三个参数,好像跟EXT学的
function $ext(dest, src, dont_overwrite) {//通常为undefined
  var src = src || {}, key;

  for (key in src)
    if (dont_overwrite !== true || typeof(dest[key]) === 'undefined')
   //如果为true检测目标对象是否已存在此属性,有就不添加了
      dest[key] = src[key];

  return dest;
};

印象中$开头的方法名定义在早期Prototypejs框架中很少出现,只有几个,自从给mootools抄了后,mootools把它发扬光大,反过来影响了Prototypejs。我讨厌这种命名方式 ,它当真把自己看成PHP吗?!

里面有一个isHash方法,用来检测其是否为javascript的Object对象,但不如jQuery的isPlainObject

  isHash = function(value) {
    return to_s.call(value) === '[object Object]';
  };

//在IE中,可能无法识别元素节点等DOM对象,因此需要进一步处理
  if (isHash(document.documentElement)) {//火狐 [object HTMLHtmlElement] IE [object Object]
    isHash = function(value) {
      return to_s.call(value) === '[object Object]' &&
        value !== null && typeof(value) !== 'undefined' &&
        typeof(value.hasOwnProperty) !== 'undefined';
    };
  }

jQuery的isPlainObject不但能区分DOM对象,还能区分那些自定义类。

        isPlainObject: function( obj ) {
            // Must be an Object.
            // Because of IE, we also have to check the presence of the constructor property.
            // Make sure that DOM nodes and window objects don't pass through, as well
            if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) {
                return false;
            }

            // Not own constructor property must be Object
            if ( obj.constructor
                && !hasOwnProperty.call(obj, "constructor")
                && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) {
                return false;
            }

            // Own properties are enumerated firstly, so to speed up,
            // if last one is own, then all properties are own.

            var key;
            for ( key in obj ) {}

            return key === undefined || hasOwnProperty.call( obj, key );
        },

下一部分将讲解其Class.Methods方法,它为子类添加许多静态方法,才能继续下面的操作。

原文地址:https://www.cnblogs.com/rubylouvre/p/1701340.html