Nej代码开发规范

一. 概述

为了统一前端开发的代码风格,以便后续代码的管理和维护,在使用前端开发框架时请遵循本文档制定的规范编写代码。 本文档涉及的规范主要包含四个方面:注释规范、命名规范、“类”模型、控件规范,另外会简要的说明系统发布的情况。

二. 注释规范

良好的注释可以增加代码的可读性和可维护性

1. 文件注释

文件注释用来说明当前文件所实现内容,主要包括说明部分和作者部分。

  • 说明部分:描述文件实现的功能、模块或接口等,如有需要增加使用说明或者范例。
  • 作者部分:记录文件的开发者名称和联系方式,用以后续的维护或者交流沟通等。
  • 依赖部分:记录当前文件直接依赖的其他文件,便于工具构建依赖关系。

注释范例如下图所示:

 /**
 * ------------------------------------------
 * 水平滑动器逻辑封装实现文件
 * @version  1.0
 * @author   genify(caijf@corp.netease.com)
 * ------------------------------------------
 */

关于这部分,如果使用Eclipse做为开发工具的话可以将其做成一个模板,在新建JS文件时可自动生成。

2. 接口注释

接口注释用来描述当前定义的接口的功能及输入输出数据,主要包括说明部分、输入部分、输出部分。

  • 说明部分:说明当前接口的功能,如有需要可增加使用说明或者范例。
  • 输入部分:说明输入数据的类型及含义。
  • 输出部分:说明输出数据的类型及含义。

注释范例如下图所示:

/**
 * 控件重置
 * @param  {Object} _options 可选配置参数
 * @return {Void}
 */
_proAbstract.__reset = function(_options){
    this.__supReset(_options);
    this.__doInitClass(_options.clazz);
    this._$appendTo(_options.parent);
};

关于这部分,如果使用Eclipse的Aptana插件,则在接口写好后直接输入“/**”然后回车会自动生成默认的注释。

3. “类”注释

“类”注释用来说明当前类的基本功能、继承关系及可接收初始输入数据,主要包括功能描述部分、继承关系部分、初始数据部分。关于这里的“类”可参阅JAVASCRIPT类模型部分的详细说明。

  • 功能描述部分:描述类所代表的对象及基本功能,如需要可增加使用说明或范例。
  • 继承关系部分:说明类的父类,以便于代码的回溯。
  • 初始数据部分:类对象在实例化时可接收这些数据做为初始信息。

注释范例如下图所示:

/**
 * 提示建议控件
 * @class   提示建议控件
 * @extends nej.ui._$$Abstract
 * @param  {Object} _options 可选配置参数,已处理参数列表如下
 *                           input     [Node|String] - 输入框节点或者ID
 *                           onselect  [Function]    - 选中触发事件
 *                           onchange  [Function]    - 输入内容变化触发事件
 */
_p._$$Suggest = NEJ.C();
  _proSuggest = _p._$$Suggest._$extend(_p._$$Abstract);
  _supSuggest = _p._$$Suggest._$supro;

三. 命名规范

本部分的规范主要为项目发布时的压缩混淆做准备

1. 命名空间

  • 规则:小写字母
  • 说明:系统的命名空间通过基础库中window.P接口增加,会以字符串的形式出现,在系统发布时不予混淆,因此选择命名空间时不易选用过于复杂的名称。

注:基础库的接口命名空间采用单个大写字母,独立项目中不宜使用此命名空间的名称规则 范例:op.tsk, lv.sys

var _  = NEJ.P,
    _o = NEJ.O,
    _e = _('nej.e'),
    _u = _('nej.u'),
    _t = _('nej.ut'),
    _p = _('nej.ui'),

2. 私有属性/接口

  • 规则:“__”+描述,即增加前缀“__”(两个下划线),变量必须有var关键字定义
  • 说明:此类属性/接口仅会在当前对象或者子类内使用,对于其他对象不可见,在系统发布时会对此类变量做混淆,因此在选择名称时以便于理解为主。

范例:如下例所示的__initNode等等

/**
 * 初始化节点
 * @return {Void}
 */
_proSuggest.__initNode = function(){
    this.__supInitNode();
    this.__sopt.body = this.__body;
};

3. 公共属性/接口

  • 规则:“_$”+描述,即增加前缀“_$”
  • 说明:此类属性或者接口可以为外部程序直接使用,系统发布时如果所有js统一发布则该类属性或者接口也会做混淆处理,因此在选择名称时以便于理解为主,名称首字母小写,遵循驼峰规则

范例:如下例所示的_$getBody等

/**
 * 取当前控件节点
 * @return {Node} 控件节点
 */
_proAbstract._$getBody = function(){
    return this.__body;
};

4. “类”对象

  • 规则:“_$$”+描述,即增加前缀“_$$”
  • 说明:此类对象可在程序任何地方使用,系统发布时如果所有js统一发布则该类名称也会做混淆处理,因此在选择名称时以便于理解为主。

范例:如下例所示的_$$Event等

_p._$$Event = NEJ.C();
  _proEvent = _p._$$Event.prototype;

5. 临时变量/参数

  • 规则:“_”+描述,即增加前缀“_”(单个下划线)
  • 说明:此类名称仅在当前接口使用,系统发布时做混淆处理,因此在选择名称时以便于理解为主。

范例:如下例所示的_options,_instance等

_p._$$Event._$allocate = function(_options){
    _options = _options||{};
    // check pool first
    var _instance = !!this.__pool
                    &&this.__pool.shift()
                    ||new this(_options);
    // reset instance, flag first
    _instance.__xxxx = !0;
    _instance.__reset(_options);
    return _instance;
};

四. “类”模型

JavaScript中本身没有“类”的概念,在实际应用中我们在JavaScript中引入“类”的概念主要出于以下几方面考虑:

  • 利用面向对象的优势
  • 控件之间的低耦合性
  • 代码的重用
  • 代码的管理维护

对于JavaScript中“类”模型的实现有很多方式,通过不断的实践我们并结合公司内部的库,项目中采用“类”模型设计的请遵循以下规范。注:请按照以下顺序创建“类”

1. “类”的定义

“类”定义统一使用C接口,范例如下

_p._$$Abstract = NEJ.C();

2. “类”的继承

通过1中定义的“类”会具备扩展接口,可以从其他“类”继承,范例如下

_p._$$Abstract = NEJ.C();
  _proAbstract = _p._$$Abstract._$extend(_t._$$Event);

3. “类”的初始化

“类”的初始化接口统一为__init

  • 接受“类”的构造参数做为输入
  • 如果需要调用父类的this.__supInit();
/**
 * 初始化
 * @return {Void}
 */
_proAbstract.__init = function(){
    this.__supInit();
    _e._$dumpCSSText();
    this.__initXGui();
    this.__initNode();
};

4. “类”接口的实现

根据“类”的需要实现其他接口,在子“类”的其他接口中如果需要掉父“类”的同名接口采用以下方式 子类实现的接口是__init,__initNode,__destory,__reset的方法,要调用父类的方法可以用 __supInit, __supInitNode, __supDestroy, __supReset 如初使化方法:

/**
 * 控件重置
 * @param  {Object} _options 可选配置参数
 * @return {Void}
 */
_proAbstract.__reset = function(_options){
    this.__supReset(_options);
    this.__doInitClass(_options.clazz);
    this._$appendTo(_options.parent);
};

如果不是上面的4类接口,假设需要调用setData的父类方法就需要如此写了

/**
 * 加载中控件
 * @class  加载中控件
 * @param  {Object} _options 可选配置参数,已处理参数列表如下:
 */
_p._$$Resize = NEJ.C();
_proResize = _p._$$Resize._$extend(_ui._$$Abstract);
_supResize = _p._$$Resize._$supro;
/**
 * 设置数据
 */
__proResize.__setData = function(){
  _supResize.__setData.apply(this,arguments);
};

五. 控件规范

控件规范请参照.

六. 文件定义

var f = function(){

};
define('{pro}js/item.js', ['{lib}ui/item/item.js', '{lib}util/template/tpl.js'], f);

七. 代码规范

1 常量

常量用全部大写字母如

var __SECONDS_IN_A_MINUTE = 60;

枚举型对象名大写枚举量用小写

var __SECONDS_TABLE = {
  minute: 60,
  hour: 60 * 60
  day: 60 * 60 * 24
}

2 空格

数值操作符(如, +/-/*/% 等)两边留空; 赋值操作符/等价判断符两边留一空格; for 循环条件中, 分号后留一空格; 变量声明语句, 数组值, 对象值及函数参数值中的逗号后留一空格; 空行不要有空格; 行尾不要有空格; 逗号和冒号后一定要跟空格; 点号前后不要出现空格; 空对象和数组不需要填入空格; 函数名末尾和左括号之间不要出现空格

var _arr = [1, 2, 3];

3 缩进

HTML和JS统一成一个tab 4个空格,一般eclipse的编辑工具都是一个tab,只是tab没有转成空格,把转成空格勾选上即可。 设置在 Window->Preferences->general->editors->text editors display tab width:4 勾选 Insert Spaces for tabs Show Print Margin Print Margin column:80 如相图:

img

4 代码一行限制

一行最多为80个字符,超过80个字符需要在适合的地方换行缩进一个tab

v._$addEvent(this.__accountTabList[i],'mousedown',
                this.__onMouseDownStopOrRightClick._$bind(this,i));

5 条件语句

条件语句的写法:

if(_isOK){

} else {

}

6 数组,对象定义

  • 单行数组或对象定义