一、变量声明的一般性方法
Qomo约定在全局空间进行变量声明时,应用var
关键字来声明,而不应当省略(尽管语法上讲能这样做)。声明时的代码格式尽可能使用如下形式:
var
v1 = 1234;
v2 = 'abcd';
或为每行声明都保留var
关键字,例如:
var v1 = 1234;
var v2 = 'abcd';
Qomo约定在函数内部声明局部变量进,使用var
关键字时可以用如下省写形式:
var
v1 = 1234, // <-- 注意行未是逗号
v2 = 'abcd';
或为每行声明保留var
关键字。
Qomo反对在函数内部声明全局变量。
二、Qomo中一些保留的命名
Qomo会将一些实现特殊的、具有“关键字”性质的功能声明为全局函数。它们通常具有特殊的名字,而且是以大写字符开始的(这看起来有点象构造器,但并不是)。这些函数名部分看起来象JavaScript的保留字,但由于javascript的命名是大小写区分的,且保留字都使用小写字符,因此这并不冲突。这些全局函数有:
Class() : 注册类
Attribute() : 快速属性声明
Interface() : 接口声明
Aggregate() : 接口聚合
Abstract() : 抽象方法
NullFunction() : 空函数/空方法
Qomo为构建系统框架,使用标准的JS原型继承的方式在全局范围内声明了一些类(构造器),用户代码应该避免覆盖这些名称。这些命名包括:
Url() : 分析一个Url地址
Ajax() : Ajax异步方式
MuEvent() : 多投事件
CustomArguments() : 标识函数入口使用了定制参数
BreakEventCast() : 标识事件投送列表被中止
JoPoint() : 切面系统中的连接点
JoPoints() : 切面系统中的连接点列表
Profilers() : 创建系统分析对象
作为习惯,Qomo保留了一些(少量的)全局的工具函数,例如:
format() : 指向String.format();
RegisterInterface() : 指向Interface.RegisterInterface()
QueryInterface() : 指向Interface.QueryInterface()
isAlias() : 检测一个命名空间是否是别名
isNamespace() : 检测一个变量是否是命名空间声明
getAllFunctions() : (用于调试与性能分析,) 列出一个代码块中调用过的函数与方法
showProfiler() : (用于调试与性能分析,) 调用$debug来显示性能分析报告
除了上述三种情况,Qomo中将尽可能少的占用全局的命名,例如函数或变量。
为此,Qomo为开发人员准备了一份资料文档,用于通告哪那些全局函数、类与命名空间被使用了,开发人员应尽可能避免出现相冲突的命名。
三、Qomo中的一些命名约定
1. 系统的特殊声明
Qomo约定以$
开始的变量为系统特殊的声明,它通常是关键的函数或可能在系统编译时被特殊处理的函数。这些函数主要包括:
$import() : 导入文件或包
$inline() : 内联代码块
$assert() : 断言
$debug() : 调试输出
$map() : 创建命名与路径的映射
$mapx() : 展开命名空间
$n2p() : 命名空间到路径的转换
$p2n() : 路径到命名空间的转换
$profilers : (对象)全局的性能分析器
$Q() : 等同于$QomoConfig
$QomoConfig() : 查询Qomo装载时或编译时的配置信息
$QomoCoreFunction : 简单地返回一个函数用来替换Function对象的toString()方法,以保护代码
此外,一些函数内的局部变量也使用$
来表明它的特殊性。
Qomo约定以_
开始的函数具有使用的上下文环境限制。主要包括:
// 以下函数仅能在类声明中使用
// - 注: Attribute()也仅能在类声明使用
_cls : 取类引用
_get : 类内部信息的getter
_set : 类内部信息的setter
此外,一些函数内的局部变量也使用_
来表明它的特殊性,或与一个没有该前缀的同名函数存在关联。
Qomo约定全大写的变量是系统保留的,或有特殊的含义的变量,该规则并不限于在函数内/外使用。例如:
_RTLOBJECT : 在Qomo替换之前的Object()构造器
_RTLERROR : 在Qomo替换之前的Error()构造器
2. 异常
Qomo约定以字符E
开始并紧邻一个大写字母表明一个异常。异常可以用数组形式来表示,例如:
ECallClassBadArguments = [8101, 'Arguments error for Class().'];
ERegClassNoname = [8102, 'With call Class(), lost class name .'];
EAccessSafeArea = [8104, 'Try Access Safe area.'];
3. 类与类类型注册
Qomo约定以大写字母开始的函数通常是类构造器,而以小写字母开始的函数是普通函数或方法。这一点是JavaScript惯用的代码风格。例如:
// 类构造器
function MyObject() {
// ..
}
// 方法或函数
function callSafeMethod() {
// ..
}
Qomo约定应当以字符T
开始,后面紧跟构造器函数名的格式对一个类进行类注册。Qomo的OOP系统和命名空间系统依赖于类注册。类注册使用Class()
函数。例如:
// 类构造器声明
function MyObject() {
// ...
}
// 类注册
TMyObject = Class(Object, 'MyObject');
4. 事件、事件句柄与事件类型
Qomo约定以On
开始的属性为事件,而以do
开始的函数通常用作事件句柄。例如:
function doCall() {
// ...
}
function MyObject() {
this.OnCall = NullFunction;
}
var obj = new MyObject();
obj.OnCall.add(doCall);
Qomo约定事件可以用一个函数声明来描述事件的接口,但这个声明除了便于开发人员使用之外,并没有任何价值。一般情况下,该声明应该以字符T
起始,紧接事件名,最后可以用Event结束。例如:
TOnCall = function(item, index) { }
TOnLoadEvent = function(filename, filenum) { }
function MyObject() {
this.OnCall = TOnCall;
this.OnLoad = TOnLoadEvent;
}
对于上面的声明来说,OnCall
与OnLoad
后面是一个空函数(NullFunction)还是一个事件类型的声明并没有关系。上面这样做,只是便于开发人员理解:当事件发生时,事件句柄可以得到怎样的入口数据。
由于“事件类型”只有声明和描述的价值,它事实上从来不会被执行。因此,可以在不同的文件中,或者相同文件的不同类、不同位置重复的声明相同名字的“事件类型”。这对程序执行不会有负面的影响。
5. 接口
Qomo约定接口是以I
字符开始来声明一个函数。接口的方法应声明为Abstract。例如:
IInterface = function() {
this.QueryInterface = Abstract;
}
6. 切面
Qomo约定应尽量以asp
或asp_
为前缀来声明切面。例如:
var asp_OnTimer = new ObjectAspect(T2, 'OnTimer', 'Event', x0);
var asp_getTopoString = new FunctionAspect(getTopoString, 'getTopoString', 'Function');
7. 内联代码
使用$inline()
可以将一个代码片断内联到当前位置执行。Qomo约定被联接的代码块应该是一个独立的文件,文件中可以包括注释,其代码体应该被包含在一个标签声明当中。这个标签声明只用于表现该代码块的特殊性,实际上没有执行价值。
该标签声明应当以_inline_
为前缀。例如:
/**
*
* 内联代码可以按JS的语言规范任意包含注释
*
*/
_inline_object_regAllInterfaceForClass: {
// register interfaces for Class's all instnaces
if (arguments.length > 2) {
Interface.RegisterInterface.apply(cls, [cls].concat(
Array.prototype.slice.call(arguments, 2)
))
}
}
8. 字符串、数组、正则等使用中的一般性规则
Qomo约定尽可能以单引号来声明字符串,而将双引号留给HTML中的属性来使用。
Qomo约定以如果在全局使用正则表达式,应该以_r_
为前缀声明,在函数局部使用正则表达式,应尽可能使用该规则。例如:
_r_event = /^On.+/;
_r_attribute = /^([gs]et)(.+)/;
JavaScript中常用数组来表达一张表格,Qomo建议这种情况下的代码应该写成如下格式:
var aTable = [
[v1, v2, v3, v4],
[v1, v2, v3, v4],
[v1, v2, this_is_long_variant, v4],
[v1, v2, v3, v4] // <-- 注意最后一行没有","号
];
尽可能用对齐的方式来避免表格修改时导致的出错。
四、Qomo中的一些特殊使用法
1. 对象(Object)的特殊用法
Qomo直接替换了构造器Object()
,因此使用new Object()
的方式会构造出一个Qomo格式的对象实例。但用户代码中仍然可以通过直接量声明来得到一个“原生的”JavaScript对象。例如:
var
obj_1 = new Object(); // Qomo对象
obj_2 = { }; // JavaScript原生的、直接量声明的对象
二者的区别在于,obj_1
因为是Qomo对象,因此必然具有如下方法和属性:
obj_1.ClassInfo
obj_1.get()
obj_1.set()
obj_1.inherited()
而obj_2由于是原生的JavaScript对象,因此使用for .. in
来列举时,不会看到任何“显式的”属性与方法。
Qomo约定用户代码不应当修改直接量形式所得到的Object的原型(prototype)。由于这种对象没有任何“显式的”属性与方法,因此它可以用来做for .. in
做一些高速的列表处理。部分内核代码使用
了这种特性。
——在firefox等mozilla引擎中,对替换后的Object()
进行原型修改会污染(我并不确定这是否更加规范)原生的、直接量声明的对象。因此本项“特殊用法”应当谨慎使用。
10. 匿名函数的特殊使用法
为了避免一段代码占用全局空间中的名称(命名污染),通常会使用匿名函数来执行一段代码。Qomo建议这种情况下使用void
来触发该匿名函数的执行。——而不是使用一对括号来做相同的事。例如:
// 推荐用法
void function() {
// 你的代码...
}();
// 不推荐用法
(function() {
// 你的代码...
})();
如果执行的结果会返回值,例如声明一个变量。则建议使用如下的结构:
var myFunc = function() {
// 一些私有变量的声明
var ...
// 你的函数
var _myFunc = function() {
//...
}
// 返回
return _myFunc;
}();
如果不对上述的_myFunc
做特殊处理(例如添加属性),那么上述的代码可以简化至:
var myFunc = function() {
// 一些私有变量的声明
var ...
// 返回你的函数
return function() {
//...
}
}();