QoBean技术文档(1):QoBean的基础技术

一、QoBean的发起

我对Qomo的不满由来以久,最根深蒂固的便是它的命名空间的实现方式:隐式地维护路径与命名空间系统。所以有一段时间,我几乎不敢看Qomo的Framework/Names/下的代码。

我对Qomo不满之处很多,但归结起来只有一条:太大太复杂。但它比那些“看起来不怎么复杂”的项目有太多特性要实现,因此复杂是必然的。我只是一直以来无法跳开一个圈子:为什么复杂的,一定不能简洁?

QoBean的触动来自于一篇文档(忘掉了出处),说在JavaScript中实现类继承只需要几行代码而已。我当时想:是啊,只需要几行代码就行了,为什么Qomo的Object.js写了20k代码,以及包括8个子文件呢?

我决定扔掉所有在Qomo Object Framework中的所有其它的(并不见得是多余的)特性,我想知道,在Qomo的设计思想中,一个最小化的“类继承”到底需要多少代码?

于是我建立了一个目录QomoMini,现在它被签入到了Qomo的项目中,改名作QoBean。QoBean是这个子项目的代码名。

二、最初的QoBean

当然,首先是从Qomo中的Object.js下手,最初的代码被精减成这样:

function Class(Parent, Name) {
  function _Create() {
    if (this.Create) this.Create.apply(this, arguments);
  }

  var Constructor = (Name instanceof Function) ? Name : eval(Name);
  var cls = new Function();
  if (Parent) Constructor.prototype = Parent.Create.prototype;

  _Create.prototype = new Constructor();
  _Create.prototype.constructor = _Create;

  (Name instanceof Function) || eval(Name + '= _Create');
  return cls;
}

TObject = Class(null, Object);

这个代码实现了几项关键功能,包括:

  • 支持类声明与类注册
  • 支持匿名类

使用示例1, 例如:

// 1. 类声明
function MyObject() {
  // 类构造周期
  // ...

  this.Create = function() {
    // 实例构造周期
  }
}

// 2. 类注册
TMyObject = Class(TObject, 'MyObject');

// 3. 创建对象
obj = new MyObject();

可见,该例仍然保持了Qomo的一般性语法。

使用示例2, 例如:

arr = [];
arr.push(Class(TObject, function() {   //<--注册一个匿名函数为匿名类
  // 类声明...
}));

// 创建对象
obj = new arr[0];

该例简单的注册了一个匿名类。匿名类是类厂等设计模式中的基础技术。

三、QoBean alpha 1

上述的Class()丢掉了几项Qomo的特性,例如obj = aClass.Create()语法,以及没有显式维护的类继承关系等等。但由于代码基本都是从Qomo的Object.js中截取出来的,因此保留了Qomo的原始状态。

接下来我们讨论如何在上述基础上实现更多的QoBean特性。

1. _Create()不需要实现为嵌套函数

上面代码中的_Create()被实现为Class()的内嵌函数,因此在执行中它处于一个闭包链的末端,这会使它的效率稍为低一点。但显然,由于_Create()没有什么地方要引用Class()内的变量,所以它可以实现在全局——但是如果直接实现在全局又会占用一个标识符。

处理的办法是使用new Function()。

2. eval(Name)的特性

上面代码中试图识别参数Name是否是一个函数,如果是函数则认为是注册匿名类——不需要重写原标识符,也不需要类名;而eval(Name)用于得到Name所指定的构造器。这一行代码写作:

var Constructor = (Name instanceof Function) ? Name : eval(Name);

然而事实上不需要这么麻烦,eval()函数执行时如果参数不是字符串就会返回该参数本身,所以更加简洁的代码是:

var Constructor = eval(Name);

3. constructor赋值操作过于啰嗦

无论如何,用两行代码来完成原型重写和constructor赋值是过于啰嗦的,我们有更好的方法。

4. 包括上述特性与修改的新版本

通过下面的修改,可以有更为精简的代码、更高的效率,以及一个外部维护的类名。

// class register util
function Class(Parent, Name) {
    var Constructor = eval(Name);
    var cls = new Function('Base', 'return new Base');
    var _Create = new Funcction('if (this.Create) this.Create.apply(this, arguments)');

    Parent && (Constructor.prototype = Parent.Create.prototype);
    cls.Create = (_Create.prototype = cls(Constructor)).constructor = _Create;

    (Name instanceof Function ? Name = 'Anonymous' : eval(Name + '= cls.Create'),
     cls.ClassName = 'T' + Name);
    return cls;
  }
};

TObject = Class(null, Object);

四、发布QoBean alpha 1的最后修改

正式发布的QoBean alpha 1比上面的代码要复杂一些。但复杂的这一部分,就是“框架”与一
个普通的工具函数之间的不同。

我们既然希望QoBean是将来的Qomo V3的基础,那么必然的,我们需要解释将来的Qomo V3是怎样的一种结构——我们需得先画好蓝图,然后再行建设。

QoBean试图在Qomo V3中添加“元系统”,用于添加新的语言特性/特性集,或者构建新的语言。

通过元系统在QoBean中创建Qomo对象模型的基本框架为:

 aClass = new MetaClass();
 aClass.Create = new MetaObject();
 aObject = new aConstructor_RegedByClass;  // or
 aObject = aClass.Create();

而在Object.js中,MetaClass与MetaObject的实现非常简单:

MetaClass = Function;
MetaObject = Function;

到了更将来的版本(事实上这个版本已经在开发中),我们会重写这两个“元(数据类型)”,
并由此构建更为复杂的语言逻辑。

此外,为了实现Qomo中的“aClass.Create()”语法,QoBean添加了一些代码,并加入了一个可选开关,大概的框架代码如下:

Class = function(ext) {
  var idx = 0;
  var code = ext ? '/
    if (this instanceof Function) {/
      var i, v=arguments, n=v.length, s="new this.Create(";/
      if (n>0) for (i=1,s+="v[0]"; i<n; i++) s += ", v[" + i +"]";/
      return eval(s+");");/
    }' : '';
  code += 'if (this.Create) this.Create.apply(this, arguments)';

  return function(Parent, Name) {
    var Constructor = eval(Name);
    var cls = new MetaClass('Base', 'return new Base');
    var _Create = new MetaObject(code);
    ...
  }
}(true);  // is delphi extand syntax.

注意上述代码中,变量code的字符串使用了特殊的语法来声明直接量:行末使用“/”,表明字符串是连续的。

其它代码请参见QoBean的下载包或SVN:

五、其它

  1. QoBean的Namespace.js中添加了命名空间的支持并重写了Class()以支持它;
  2. QoBean的代码包包含更多的示例。
  3. 所谓“类继承系统”是指继承关系的维护,不包括Qomo中的get/set,以及inherited等特性。