前端编码规范

2021-11-08 14:07:45 浏览数 (1)

编码规范 一、 HTML编码规范

  • 1.代码风格
  • 1.1 缩进与换行

[强制] 使用4个空格作为一个缩进层级。 [建议] 每行不得超过120个字符。

  • 1.2 命名

[强制] class 必须单词全字母小写,单词间以 – 分隔。 [强制] class必须代表相应模块或部件的内容或功能,不得以样式信息进行命名。 [强制] 元素 id 必须保证页面唯一。 [强制] 同一页面,应避免使用相同的 nameid。 [建议] id 建议单词全字幕小写单词间以 – 分隔。同项目必须保持风格一致。 [建议] id、class命名,在避免冲突并描述清楚的前提下尽可能短。

  • 1.3 标签

[强制] 标签名必须使用小写字母。 [强制] 对于无需自闭合的标签,不允许自闭合。 常见无需自闭合的标签有input、br、img、hr等 示例:

代码语言:javascript复制
<input type="text" name="title">     //good
<input type="text" name="title" />     //bad
复制代码

[强制] 对 HTML5 中规定允许省略的闭合标签,不允许省略闭合标签。 [强制] 标签使用必须符合标签嵌套规则。比如div不得置于p中,tbody必须至于table中。

  • 1.4 属性

[强制] 属性名必须使用小写字母。 例如:

代码语言:javascript复制
<table cellspacing="0">...</table>    //good
<table cellSpacing="0">...</table>    //bad
复制代码

[强制] 属性值必须用双引号包围。 例如:

代码语言:javascript复制
<script src="babel.js"></script>    //good
<script src=’babel.js’></script>     //bad
复制代码

[建议] 布尔类型的属性,建议不添加属性值。 [建议] 自定义属性建议以 xxx- 为前缀,推荐使用 data- 。

  • 2.通用
  • 2.1 DOCTYPE

[强制] 使用 HTML5 的 doctype 来启用标准模式,建议使用大写的 DOCTYPE。 [建议] 启用 IE Edge 模式。

代码语言:javascript复制
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
复制代码

[建议] 在 html 标签上设置正确lang属性。

  • 2.2 编码

[强制] 页面必须使用精简模式,明确指定字符编码。指定字符编码的 meta 必须是 head 的第一个直接子元素。 [建议] HTML 文件使用 BOM 的 UTF-8 编码。

  • 2.3 CSS 和 JavaScript 的引入。

[强制] 引入 CSS 时必须指明 rel=”stylesheet”。 [建议] 引入 CSS 和 JavaScript 时无须指明 type 属性。 [建议] 在 head 中引入页面需要的所以 CSS 资源。 [建议] JavaScript 应当放在页面末尾,或采用异步加载。

  • 3.Head
  • 3.1 title

[强制] 页面必须包含 title 标签声明标题。 [强制] title 必须作为 head 的直接子元素,并紧随 charset 声明之后。

  • 3.2 viewport

[建议] 若页面欲对移动页面友好,需指定页面的 viewport。

  • 4.图片

[强制] 禁止 img 的src 取值为空。延迟加载的图片也要增加默认的 src。 [强制] 为图片添加 alt 属性。 [建议] 避免为 img 添加不必要的 title 属性。 [建议] 有下载需求的图片采用 img 标签实现,无下载需求的图片采用 CSS 背景图实现。

  • 5.表单
  • 5.1 控件标题

[强制] 有文本标题的控件必须使用 label 标签将其与其标签相关联。 两种方式: 1.将控件置于label内。 2.label 的 for 属性指向控件的 id。

  • 5.2 按钮

[强制] 使用 button 元素时必须指明 type 属性值。 [建议] 尽量不要使用按钮类元素的 name 属性。

  • 6.多媒体

[建议] 当在现代浏览器中使用 audio 以及 video 标签来播放音频、视频时,应当注意格式。 音频格式: MP3、WAV、Ogg 视频格式: MP4、WebM、Ogg [建议] 在支持 HTML5 的浏览器中优先使用 audio 和 video 标签来定义音视频元素。 [建议] 只在必要的时候开启音视频的自动播放。

  • 7.模板中的 HTML

[建议] 模板代码的缩进优先保证 HTML 代码的缩进规则。 [建议] 模板代码应以保证 HTML 单个标签语法的正确性为基本原则。 [建议] 在循环处理模板数据构造表格时,若要求每行输出固定的个数,建议先将数据分组,之后在循环输出。

二、CSS编码规范

  • 1.命名
  • 1.1 文件命名

常用的文件命名: 全局:global.css 结构:layout.css 模块:module.css 主题:theme.css 较长的文件名必须以 – 中横杠符连接,项目里面的私有样式文件:项目名-业务模块名称.css

  • 1.2 选择器命名

[强制] 在不是必须的情况下尽可能不用id选择器。

  • 1.选择器名字全小写,不得使用大写。
  • 2.较长选择器名字之间使用-中横杆连接。
  • 3.当判断容易出现命名冲突的时候,命名需按规则:模块名-你的选择器名,如果出现多层级选择器的情况(应尽量避免超过3级的情况),每个层级间使用-中横杆连接,不建议直接使用嵌套。

[建议] 常用的选择器命名

  • 1代码风格
  • 1.1 缩进

[强制] 统一使用 4 个空格缩进,不得使用 tab 和 2 个空格(没规范前的缩进方式不管)。

  • 1.2 空格

[强制] 选择器跟 { 之间 必须包含空格。 例:

代码语言:javascript复制
/* good */
.selector {
}

/* bad */
.selector{
}
复制代码

[强制] 属性跟 : 之间不能有空格, : 跟属性之间必须包含空格。

代码语言:javascript复制
.selector {
	color: white;
}

.selector {
	color:white; /* 或 color : white;*/
}
复制代码

[强制] >、 、~ 选择器的两边各保留一个空格。

  • 1.3换行

[强制] 一个rule中有多个选择器时,选择器必须换行。 [强制] 属性值之间必须换行。 [建议] 对于超长的样式属性值,可在 空格 或 , 处换行。

  • 1.4行长度

[强制] 每行不得超过 120 个字符,除非单行不可分割(例如url超长)。

  • 2.值与单位
  • 2.1文本

[强制] 文本内容必须用双引号包围。

  • 2.2数值

[强制] 数值为 0 – 1 之间的小数,省略整数部分的0。

  • 2.3单位

[强制] 数组为 0 的属性值需省略单位。

  • 2.4 url()

[强制] url() 函数中的路径不加引号。 [建议] url() 函数中的绝对路径可省去协议名。

  • 2.5颜色

[强制] RGB颜色值必须使用十六进制形式 #3f3f3f。不允许使用 rgb()。带有alpha(不透明度)的颜色信息可以使用 rgba()。不使用 rgba() 时每个逗号后须保留一个空格。 [强制] 颜色值可缩写时,必须使用缩写形式。 [强制] 颜色值不可使用颜色单词。(如: red、green 等) [建议] 颜色值中的英文字母使用小写,如果采用大写字母,则必须保证同一项目内是一致的。

  • 3.通用
  • 3.1选择器

[强制] DOM节点的 id、class 属性赋值时 = 之间不得有空格,属性值必须用双引号包围,不得用单引号。 [强制] 如无必要,尽量不使用 id 选择器,给 id、class 选择器设置属性时不需要添加类型选择器进行限定。 [强制] id 选择器不需嵌套其他选择器。

  • 3.2属性缩写

[建议] 在可以使用缩写的情况下,尽量使用属性缩写。 [建议] 使用 border、margin、padding 等缩写时,应注意确实需要设置多个方向的值时才使用缩写,避免其他方向的有用值被覆盖掉。

  • 3.3属性书写顺序

[建议] 按如下顺序书写:

代码语言:javascript复制
1.位置属性(position, top, right, z-index , display, float, overflow 等)
2.大小(width,height,padding,margin,border)
3.文字系列(font,line-height,letter-spacing,color-text-align等)
4.视觉(background,color,list-style等)
5.其他(animation,transition等)
复制代码
  • 3.4 变换与动画

[强制] 使用 transition 时应指定 transition-property,不用 all。

  • 3.5 属性前缀

[建议] 属性的私有前缀按长到短排列,按 : 对其 例:

代码语言:javascript复制
/* good */
.tab {
    -webkit-transition: color .5s;
       -moz-transition: color .5s;
            transition: color .5s;
}

/* bad */
/* bad */
.tab {
    -webkit-transition: color .5s;
    -moz-transition: color .5s;
    transition: color .5s;
}
复制代码

三、JavaScript编码规范

  • 1.代码风格
  • 1.1文件

[建议] JavaScript 文件使用无 BOM 的 UTF-8 编码。 [建议] 在文件结尾处,保留一个空行。

  • 1.2缩进

[强制] 使用 4 个空格做为一个缩进层级,不允许使用 2 个空格或 tab 字符。 [强制] switch 下的 case 和 default 必须增加一个缩进层级。

  • 1.3 空格

[强制] 二元运算符两侧必须有一个空格,一元运算符与操作对象之间不允许有空格。 [强制] 用作代码块起始的左花括号 { 前必须有一个空格。 [强制] if / else / for / while / function / switch / do / try / catch / finally 关键字后,必须有一个空格。 [强制] 在对象创建时,属性中的 : 之后必须有空格,: 之前不允许有空格。 [强制] 函数声明、具名函数表达式、函数调用中,函数名和 ( 之间不允许有空格。 [强制] , 和 ; 前不允许有空格。 [强制] 在函数调用、函数声明、括号表达式、属性访问、if / for / while / switch / catch 等语句中,() 和 [] 内津贴括号部分不允许有空格。 [强制] 单行声明的数组与对象,如果包含元素,{} 和 [] 内紧贴括号部分不允许包含空格。 [强制] 行尾不得有多余的空格。

  • 1.4 换行

[强制] 每个独立语句结束后必须换行。 [强制] 每行不得超过 120 个字符。 [强制] 运算符处换行时,运算符必须在新行的行首。

代码语言:javascript复制
/* good */
var result = number1   number2   number3
  number4   number5;
/* bad */
var result = number1   number2   number3  
number4   number5;
复制代码

[强制] 在函数声明、函数表达式、函数调用、对象创建、数组创建、for语句等场景中,不允许在 , 或 ; 前换行。 [建议] 不同行为或逻辑的语句集,使用空行隔开,更易阅读。 [建议] 在语句的行长度超过 120 时,根据逻辑条件合理缩进。 [建议] 对于 if...else...、try...catch...finally 等语句,推荐使用在 } 号后添加一个换行的风格,使代码层次结构更清晰,阅读性更好。

  • 1.5 语句

[强制] 不得省略语句结束的分号。 [强制] 在 if / else / for / do / while 语句中,即使只有一行,也不得省略块{…}。 [强制] 函数定义结束不允许添加分号。

代码语言:javascript复制
// 如果是函数表达式,分号是不允许省略的。
var funcName = function() { 
};
复制代码

[强制] IIFE 必须在函数表达式外添加 ( , 非 IIFE 不得在函数表达式外添加 ( 。 IIFE = Immediately-Invoked Function Expression (能够让代码在阅读的一开始就能判断函数是否立即被调用,进而明白接下来代码的用途。而不是一直拖到底部才恍然大悟。) 例:

代码语言:javascript复制
// good
var task = (function () {
   // Code
   return result;
})();

var func = function () {
};


// bad
var task = function () {
    // Code
    return result;
}();
var func = (function () {
});
复制代码
  • 1.6 命名

[强制] 变量 使用 Camel命名法。 [强制] 函数 使用 Camel命名法。 [强制] 函数的 参数 使用 Camel命名法。 [强制] 类的 参数 使用 Camel命名法。 [强制] 类 使用 Pascal命名法。 [强制] 类的 方法 / 属性 使用 Camel命名法。 [强制] 枚举变量 使用 Pascal命名法,枚举的属性 使用 全部字母大写,单词间下划线分隔 的命名方式。 [强制] 命名空间 使用 Camel命名法。 [强制] 由多个单词组成的缩写,在命名中,根据当前命名法和出现的位置,所以字母的大小写保持一致。 [强制] 类名 使用 名词。 [建议] 函数名 使用 动宾短语。 [建议] Boolean 类型的变量使用 is 或 has 开头。 [建议] Promise对象 用 动宾短语的进行时 表达。

  • 1.7 注释
  • 1.7.1 单行注释

[强制] 必须独占一行。 // 后跟一个空格,缩进与下一行被注释说明的代码一致。

  • 1.7.2 多行注释

[建议] 避免使用 // 这样的多行注释。有多行注释内容时,使用多个单行注释。

  • 1.7.3 文档化注释

[强制] 为了便于代码阅读和自文档化,以下内容必须包含 /**…*/ 形式的块注释中。 解释:

  1. 文件 2.namespace 3. 类 4. 函数或方法 5.类属性
  2. 事件 7. 全局变量 8. 常量 9. AMD 模块

[强制] 文档注释前必须空一行。 [建议] 自文档化身为文档说明what,而不是how。

  • 1.7.4类型定义

[强制] 类型定义都是以 { 开始,以 } 结束。 常用的类型如: {string}, {number}, {boolean}, {Object},{Function},{RegExp},{Array},{Date}。 [强制] 对于基本类型 {string}, {number}, {boolean},首字母必须小写。

  • 1.7.5 文件注释

[强制] 文件顶部必须包含文件注释,用 @file 标识文件说明。 示例:

代码语言:javascript复制
/**
* @file Describe the file
*/
复制代码

[建议] 文件注释中可以用 @author 标识开发者信息。 @author 中的名字不允许被删除。任何劳动成果都应该被尊重。 1.7.6命名空间注释 [建议] 命名空间使用 @namespace 标识。 1.7.7类注释 [建议] 使用 @class 标记类或构造函数。 示例:

代码语言:javascript复制
/**
 * 描述
 *
 * @class
 */
function Developer() {
    // constructor body
}
复制代码

示例: [建议] 使用 @extends 标记类的继承信息。

代码语言:javascript复制
/**
 * 描述
 *
 * @class
 * @extends Developer
 */
function Fronteer() {
    Developer.call(this);
    // constructor body
}
util.inherits(Fronteer, Developer);
复制代码

[强制] 使用包装方式扩展类成员时, 必须通过 @lends 进行重新指向。 解释: 没有 @lends 标记将无法为该类生成包含拓展类成员的文档。 [强制] 类的属性或方法等成员信息使用 @public / @protected / @private 中的任意一个,指明可访问性。 示例:

代码语言:javascript复制
/**
* 类描述
*
* @class
* @extends Developer
*/
function Fronteer() {
Developer.call(this);
// constructor body
}

util.extend(
Fronteer.prototype,
/** @lends Fronteer.prototype */{
_getLevel: function () {
// TODO
}
}
);
复制代码

[强制] 类的属性或方法等成员信息使用 @public / @protected / @private 中的一个,指明可访问性。 示例:

代码语言:javascript复制
/**
 * 类描述
 *
 * @class
 * @extends Developer
 */
var Fronteer = function () {
    Developer.call(this);

    /**
     * 属性描述
     *
     * @type {string}
     * @private
     */
    this._level = 'T12';

    // constructor body
};
util.inherits(Fronteer, Developer);
复制代码
代码语言:javascript复制
/**
 * 方法描述
 *
 * @private
 * @return {string} 返回值描述
 */
Fronteer.prototype._getLevel = function () {
};
复制代码
  • 1.7.8函数/方法注释

[强制] 函数/方法注释必须包含函数声明,有参数和返回值时必须使用注释标记。 [强制] 参数和返回值注释必须包含类型信息和说明。 [建议] 当函数是内部函数,外部不可访问时,可以使用 @inner 标识。 [强制] 对 Object 中各项的描述, 必须使用 @param 标识。

代码语言:javascript复制
/**
 * 函数描述
 *
 * @param {Object} option 参数描述
 * @param {string} option.url option项描述
 * @param {string=} option.method option项描述,可选参数
 */
function foo(option) {
    // TODO
}
复制代码
  • 1.7.9事件注释

[强制] 必须使用 @event 标识事件,事件参数的标识与方法描述的参数标识相同。 [强制] 在会广播事件的函数前使用 @fires 标识广播的事件,在广播事件代码前使用 @event 标识事件。 [建议] 对于事件对象的注释,使用 @param 标识,生成文档时可读性更好。

  • 1.7.10常量注释

[强制] 常量必须使用 @const 标记,并包含说明和类型信息。 示例:

代码语言:javascript复制
/**
 * 常量说明
 *
 * @const
 * @type {string}
 */
var REQUEST_URL = 'myurl.do';
复制代码
  • 1.7.11复杂类型注释

[建议] 对于类型未定义的复杂结构的注释,可以使用 @typedef 标识来定义。

  • 1.7.12 AMD 模块注释

[强制] AMD 模块使用 @module 或 @exports 标识。 [强制] 对于已使用 @module 标识为 AMD模块 的引用,在 namepaths 中必须增加 module: 作前缀。

  • 1.7.13细节注释

[建议] 细节注释遵循单行注释的格式。说明必须换行时,每行是一个单行注释的起始。 [强制] 有时我们会使用一些特殊标记进行说明。特殊标记必须使用单行注释。常用标记: 解释:

  1. TODO:有功能待实现。此时需要对将要实现的功能进行简单说明。
  2. FIXME:该处代码允许没问题,但可能由于时间赶或者其他原因,需要修正。此时需要对如何修正进行简单说明。
  3. HACK:为修正某些问题而写的不太好或者使用了某些诡异手段的代码。此时需要对思路或诡异手段进行描述。
  4. XXX:该处存在缺陷。此时需要对陷阱进行描述。

2语言特性

  • 2.1变量

[强制] 变量使用前必须通过 var 定义。 [强制] 每个 var 只能声明一个变量。 [强制] 变量必须 即用即声明,不得在函数或其他形式的代码块起始位置统一声明所有变量。 解释: 变量声明与使用的距离越远,出现的跨度越大,代码的阅读与维护成本越高。虽然JavaScript的变量时函数作用域,还是应该根据编程中的意图,缩小变量出现的距离空间。 示例:

代码语言:javascript复制
// good
function kv2List(source) {
    var list = [];

    for (var key in source) {
        if (source.hasOwnProperty(key)) {
            var item = {
                k: key,
                v: source[key]
            };
            list.push(item);
        }
    }

    return list;
}

// bad
function kv2List(source) {
    var list = [];
    var key;
    var item;

    for (key in source) {
        if (source.hasOwnProperty(key)) {
            item = {
                k: key,
                v: source[key]
            };
            list.push(item);
        }
    }

    return list;
}
复制代码
  • 2.2 条件

[强制] 在 Equality Expression 中使用类型严格的 === 。仅当判断 null 或 undefined时,允许使用 == null 。 [建议] 尽可能使用简介的表达式。 示例:

代码语言:javascript复制
// 字符串为空

// good
if (!name) {
    // ......
}

// bad
if (name === '') {
    // ......
}

// 字符串非空

// good
if (name) {
    // ......
}

// bad
if (name !== '') {
    // ......
}

// 数组非空

// good
if (collection.length) {
    // ......
}

// bad
if (collection.length > 0) {
    // ......
}

// good
if (!notTrue) {
    // ......
}

// bad
if (notTrue === false) {
    // ......
}

// null 或 undefined

// good
if (noValue == null) {
  // ......
}

// bad
if (noValue === null || typeof noValue === 'undefined') {
  // ......
}
复制代码

[建议] 按执行频率排列分支的顺序。 解释: 按执行频率排列分支顺序的好处是:

  1. 容易找到最常见的情况,增加可读性。
  2. 提高执行效率。

[建议] 对于相同变量或表达式的多值条件,用 switch 代替 if 。 示例:

代码语言:javascript复制
// good
switch (typeof variable) {
    case 'object':
        // ......
        break;
    case 'number':
    case 'boolean':
    case 'string':
        // ......
        break;
}

// bad
var type = typeof variable;
if (type === 'object') {
    // ......
} 
else if (type === 'number' || type === 'boolean' || type === 'string') {
    // ......
}
复制代码

[建议] 如果函数或全局中的 else 块后没有任何语句,可以删除 else。

  • 2.3 循环

[建议] 不要在循环体中包含函数表达式,事先将函数提取到循环体外。 解释: 循环体中的函数表达式,运行过程中会生成循环次数个函数对象。 示例:

代码语言:javascript复制
// good
function clicker() {
    // ......
}

for (var i = 0, len = elements.length; i < len; i  ) {
    var element = elements[i];
    addListener(element, 'click', clicker);
}


// bad
for (var i = 0, len = elements.length; i < len; i  ) {
    var element = elements[i];
    addListener(element, 'click', function () {});
}
复制代码

[建议] 对循环内多次使用的不变值,在循环外用变量缓存。 [建议] 对有序集合进行遍历时,缓存 length。 [建议] 对有序集合进行顺序无关的遍历时,使用逆序遍历。 解释:逆序遍历可以节省遍历,代码比较优化。 示例:

代码语言:javascript复制
var len = elements.length;
while (len--) {
    var element = elements[len];
    // ......
}
复制代码
  • 2.4 类型
  • 2.4.1 类型检测

[建议] 类型检测优先使用 typeof 。对象类型检测使用 instanceof 。null 或undefined 的检测使用 ==null 。

  • 2.4.2 类型转换

[建议] 转换成 string 时,使用 ‘’ 。 [建议] 转换成 number 时,通常使用 。 [建议] string 转换成 number,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt 。 示例: var width = '200px'; parseInt(width, 10); [强制] 使用 parseInt 时,必须指定进制。 示例: // good parseInt(str, 10);

// bad parseInt(str); [建议] 转换成 Boolean 时,使用 !! 。 示例: var num = 3.14; !!num; [建议] number 去除小数点,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt。

  • 2.5 字符串

[强制] 字符串开头和结尾使用单引号 ‘ 。 解释:

  1. 输入单引号不需要按住shift,方便输入。
  2. 实际使用中,字符串经常用来拼接HTML。为方便HTML中包含双引号而不需要转义写法。

[建议] 使用 拼接字符串。 [建议] 复杂的数据到视图字符串的转换过程,选用一种模板引擎。

  • 2.6 对象

[强制] 使用对象字面量 {} 将创建新 object 。 [强制] 对象创建时,如果一个对象的所有 属性 均可以不添加引号,则所有 属性 不得添加引号。 [强制] 对象创建时,如果任何一个 属性 需要添加引号,则所有 属性 必须添加 ' 。 [强制] 不允许修改和拓展任何原生对象和宿主对象的原型。 示例: // 以下行为绝对禁止

代码语言:javascript复制
String.prototype.trim = function () {
};
复制代码

[建议] 属性访问时,尽量使用 . 。 解释: 属性名符合 Identifier (标识符) 的要求,就可以通过 . 来访问,否则就只能通过 [expr] 方式访问。 通常在 JavaScript 中声明的对象,属性命名是使用 Camel 命名法,用 . 来访问更清晰简洁。部分特殊的属性(比如来自后端的JSON),可能采用不寻常的命名方式,可以通过 [expr] 方式访问。 示例: info.age; info['more-info']; [建议] for in 遍历对象时,使用 hasOwnProperty 过滤掉原型中的属性。 示例:

代码语言:javascript复制
var newInfo = {};
for (var key in info) {
    if (info.hasOwnProperty(key)) {
        newInfo[key] = info[key];
    }
}
复制代码
  • 2.7 数组

[强制] 使用数组字面量 [] 创建新数组,除非想要创建的时指定长度的数组。 [强制] 遍历数组不使用 for in 。 [建议] 不因为性能的原因自己实现数组排序功能,尽量使用数组的 sort 方法。 解释: 自己实现的常规排序算法,在性能上并不优于数组默认的 sort 方法。以下两种场景可以自己实现排序:

  1. 需要稳定的排序算法,达到严格一致的排序结果。
  2. 数据特点鲜明,适合使用桶排。

[建议] 情况数组使用 .length = 0 。

  • 2.8 函数
  • 2.8.1 函数的长度

[建议] 一个函数的长度控制在 50 行以内。

  • 2.8.2 参数的设计

[建议] 一个函数的参数控制在 6 个以内。 解释: 除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 6 个以内,过多参数会导致维护难度增大。某些情况下,如使用 AMD Loader 的 require 加载多个模块时,其 callback 可能会存在较多参数,因此对函数参数的个数不做强制限制。 [建议] 通过 options 参数传递非数据输入型参数。

  • 2.8.3 闭包

[建议] 在适当的时候将闭包内打对象置为 null 。 2.8.4 空函数 [建议] 空函数不使用 new Function() 的形式。 示例:javascript

代码语言:javascript复制
var emptyFunction = function () {};
复制代码

[建议] 对于性能有高要求的场合,建议存在一个空函数的常量,供多处使用共享。

  • 2.9 面向对象

[强制] 类的继承方案,实现时需要修正 constructor 。 解释: 通常使用其他 library 的类继承方案都会进行 constructor 修正。如果是自己实现的类继承方案,需要进行 constructor 修正。 示例:

代码语言:javascript复制
/**
 * 构建类之间的继承关系
 * 
 * @param {Function} subClass 子类函数
 * @param {Function} superClass 父类函数
 */
function inherits(subClass, superClass) {
    var F = new Function();
    F.prototype = superClass.prototype;
    subClass.prototype = new F();
    subClass.prototype.constructor = subClass;
}
复制代码

[建议] 声明类时,保证 constructor 的正确性。 示例:

代码语言:javascript复制
function Animal(name) {
    this.name = name;
}

// 直接prototype等于对象时,需要修正constructor
Animal.prototype = {
    constructor: Animal,

    jump: function () {
        alert('animal '   this.name   ' jump');
    }
};

// 这种方式扩展prototype则无需理会constructor
Animal.prototype.jump = function () {
    alert('animal '   this.name   ' jump');
};
复制代码

[建议] 属性在构造函数中声明,方法在原型中声明。 解释: 原型对象的成员被所有实例共享,能节约内存占用。所以编码时我们应该遵守这样的原则:原型对象包含程序不会修改的成员,如方法函数或配置项。

代码语言:javascript复制
function TextNode(value, engine) {
    this.value = value;
    this.engine = engine;
}

TextNode.prototype.clone = function () {
    return this;
};
复制代码

[强制] 自定义事件的 事件名 必须全小写。 [强制] 自定义事件只能有一个 event 参数。如果事件需要传递较多信息,应仔细设计事件对象。 [建议] 设计自定义事件时,应考虑禁止默认行为。 解释: 常见禁止默认行为的方式有两种:

  1. 事件监听函数中 return false。
  2. 事件对象中包含禁止默认行为的方法,如preventDefault 。
  • 2.10 动态特性
  • 2.10.1 eval

[强制] 避免使用直接 eval 函数。 [强制] 尽量避免使用 eval 函数。

  • 2.10.2 动态执行代码

[建议] 使用 new Function 执行动态代码。 解释: 通过 new Function 生成的函数作用域时全局作用域,不会影响当前的本地作用域。如果有动态代码执行的需求,建议使用 new Function。 示例:

代码语言:javascript复制
var handler = new Function('x', 'y', 'return x   y;');
var result = handler($('#x').val(), $('#y').val());
复制代码
  • 2.10.3 with

[建议] 尽量不要使用 with 。 解释: 使用 with 可能会增加代码的复杂度,不利于阅读和管理;也会对性能有影响。大多数使用 with 的场景都能使用其他方式较好的替代。所以,尽量不要使用 with。

  • 2.10.4 delete

[建议] 减少delete的使用。 解释: 如果没有特别的需求,减少或避免使用delete。delete的使用会破坏部分 JavaScript 引擎的性能优化。

  • 2.10.5 对象属性

[建议] 避免修改外部传入的参数。 [建议] 具备强类型的设计。

  • 3.浏览器环境
  • 3.1 模块化
  • 3.1.1 AMD

[强制] 使用 AMD 作为模块定义。 解释: AMD 作为由社区认可的模块定义形式,提供多种重载提供灵活的使用方式,并且绝大多数优秀的 Library 都支持 AMD,适合作为规范。 目前,比较成熟的 AMD Loader有:

  1. 官方实现的 require.js
  2. 百度自己实现的 esl

[强制] 模块 id 必须符合标准。 解释: 模块 id 必须符合以下约束条件:

  1. 类型为 string,并且是由 / 分割的一系列 terms 来组成。例如:this/is/a/module。
  2. term 应该符合 [a-zA-Z0-9_-] 规则。
  3. 不应该有 .js 后缀。
  4. 跟文件的路径保持一致。
  • 3.1.2 define

[建议] 定义模块时不要指明 id 和 dependencies 。 解释: 在 AMD 的设计思想里,模块名称是和所在路径相关的,匿名的模块更利于封包和迁移。模块依赖应在模块定义内部通过 local require 引用。所以,推荐使用 define(factory) 的形式进行模块定义。 [建议] 使用 return 来返回模块定义。

  • 3.1.3 require

[强制] 全局运行环境中,require 必须以 async require 形式调用。 解释:模块的加载过程时异步的,require 必须以 async require 形式调用。

[强制] 模块定义中只允许使用 local require,不允许使用 global require。 解释:在模块定义中使用 global require,对封装性是一种破坏。在 AMD 里,global require 是可以被重命名的。并且 Loader 甚至没有全局的 require 变量,而是用 Loader 名称做为 global require。模块定义不应该依赖使用的 Loader。

[强制] Package在实现时,内部模块的 require 必须使用 relative id。 解释:对于任何可能通过 发布-引入 的形式复用的第三方库、框架、包,开发者所定义的名称不代表使用者使用的名称。因此不要基于任何名称的假设。在实现源码中,require 自身的其它模块时使用 relative id。

[建议] 不会被调用的依赖模块,在 factory 开始处统一 require。 解释: 有些模块是依赖的模块,但不会在模块实现中被直接调用,最为典型的是 css / js / tpl 等 Plugin 所引入的外部内容。此类内容建议放在模块定义最开始处统一引用。

  • 3.2 DOM
  • 3.2.1 元素获取

[建议] 对于单个元素,尽可能使用 document.getElementById 获取,避免使用document.all。 [建议] 对于多个元素的集合,尽可能使用 context.getElementsByTagName 获取。其中 context 可以为 document 或其他元素。指定 tagName 参数为 * 可以获得所有子元素。 [建议] 遍历元素集合时,尽量缓存集合长度。如需多次操作同一集合,则应将集合转为数组。

  • 3.2.2 样式获取

[建议] 获取元素实际样式信息时,应使用getComputedStyle 或 currentStyle。

  • 3.2.3 样式设置

[建议] 尽可能通过为元素添加预定义的 className 来改变元素样式,避免直接操作 style 设置。 [强制] 通过 style 对象设置元素样式时,对于带单位非 0 值的属性,不允许省略单位。

  • 3.2.4 DOM 操作

[建议] 操作 DOM 时,尽量减少页面 reflow。 解释: 页面 reflow 时非常耗时的行为,非常容易导致性能瓶颈。下面一些场景会触发浏览器的 reflow:

  1. DOM元素的添加、修改(内容)、删除。
  2. 应用新的样式或者修改任何影响元素布局的属性。
  3. Resize浏览器窗口、滚动页面。
  4. 读取元素的某些属性(offsetLeft、offsetTop、offsetHeight、offsetWidth、scrollTop/Left/Width/Height、clientTop/Left/Width/Height、getComputedStyle()、currentStyle(in IE)) 。

[建议] 尽量减少 DOM 操作。 解释: DOM 操作也是非常耗时的一种操作,减少 DOM 操作有助于提高性能。举一个简单的例子,构建一个列表。我们可以用两种方式:

  1. 在循环体中 createElement 并 append 到父元素中。
  2. 在循环体中拼接 HTML 字符串,循环结束后写父元素的 innerHTML。

第一种方法看起来比较标准,但是每次循环都会对 DOM 进行操作,性能极低。在这里推荐使用第二种方法。

  • 3.2.5 DOM事件

[建议] 优先使用 addEventListener / attachEvent 绑定事件,避免直接在HTML属性中上午 expando 属性绑定事件处理。 解释:expando 属性绑定事件容易导致互相覆盖。

[建议] 使用 addEventListener 时第三个参数使用 false 。 解释:标准浏览器中的 addEventListener 可以通过第三个参数指定两种时间触发模型:冒泡和捕获。而 IE 的 attachEvent 仅支持冒泡的事件触发。所以为了保持一致性,通常 addEventListener 的第三个参数都为 false。

[建议] 在没有事件自动管理的框架支持下,应持有监听器函数的引用,在适当时候(元素释放、页面卸载等)移除添加的监听器。

0 人点赞