blog

JavaScript开发规范

前言

本文档的目标是JavaScript代码风格保持一致,容易被理解和被维护。

项目规范

  • 项目必须有 README.md 描述文件
    • 项目描述
    • 引用技术描述
    • 代码风格描述
    • 目录结构
    • 运行环境
    • 开发命令,运行命令,以及其他命令
    • 复杂流程介绍等

代码风格

  • 建议JavaScript使用无BOM的UTF-8编码
  • 建议在文件结尾处保留一个空格
  • 使用4个空格作为一个缩进层级,不允许使用2个空格或者tab字符
  • switch下的case和default必须增加一个缩进
// good
switch () {
    case '1':
        break;
    default:
        break;
}

代码空格

  • 二元运算符两侧必须有一个空格,一元运算符与操作对象之间不允许有空格
// good
var a = !arr.length;
a++;
++a;
a = b + c;
// bad
var a=!arr.length;
a=b+c;
  • 用作代码块起始的左花括号 { 前必须有一个空格
  • if / else / else if / for / while / function / switch / do / try / catch / finally 关键字后,必须有一个空格
// good
if () {}
(function () {})();
while () {}
// bad
if(){}
(function(){})()
  • 在对象创建时,属性中的 : 之后必须有一个空格, : 之前不允许有空格
// good
var obj = {
    a: 1,
    b: 1
};
// bad
var obj = {
    a:1, // bad
    b : 1, // bad
    c :1 // bad
};
  • 在函数声明,具名函数表达式,函数调用中,函数名和 ( 之间不允许有空格
// good
function funName() {}
var funName = function funName2() {}
// bad
function funName () {}
  • , 和 ; 前不允许有空格,如果不位于行尾, , 和 ; 后必须跟一个空格
// good
callback(a, b);
// bad
callback(a , b) ;
  • 在函数调用,函数声明,括号表达式,属性访问, if / for / while / switch / catch 等语句中,() [] 内紧贴括号部分不允许有空格
// good
callback(params1, params2, params3);
list(this.data[this.arr[i]]);
if (length > arr.length) {}

// bad
callback( params1, params2, params3 );
list( this.data[ this.arr[ i ] ] );
if ( length > arr.length ) {}
  • 单行声明的数组与对象,如果包含元素, {}, [] 内紧贴括号部分不允许包含空格
  • 声明包含元素的数组与对象,只有当内部元素的形式比较简单时,才允许写在一行,元素复杂的情况,应该换行书写。
  • 在函数声明,函数表达式,函数调用,对象创建,数组创建, for语句等场景中,不允许在 , ;前换行。
// good
var arr = [];
var arr = [1, 2, 3];
var obj = {};
var obj = {a: '1', b: 'j'};
var obj = {
    name: 'obj',
    sex: 1,
    age: 1
};
// bad
var arr = [ ];
var arr = [ 1, 2, 3 ];
var obj = { };
var obj = { a: '1', b: '2' };
var obj = {name: 'obj', sex: 1, age: 1};
var obj = {
    name: 'obj'
    , sex: 1
};
  • import语句中{}内侧紧贴括号部分不允许有空格
// good
import {mapGetters, mapState} from 'vuex';
// bad
import { mapGetters, mapState } from 'vuex';
  • 行尾不得有空格
  • 每个独立语句结束后必须换行
  • 每行不得超过120个字符
  • 超长的不可分割的代码允许例外,比如复杂的正则表达式,长字符串不例外
  • 运算符处换行时,运算符必须在新行的行首
// good
var isTrue = user.isTrue
    && info.isTrue
    && content.isTrue
    || info.length;

var result = num1
    + num2
    + num3
    + num4;

var html = ''
    + '<div>'
    +     '<div>'
    +         '<h1></h1>'
    +     '</div>'
    + '</div>';

var html = [
    '<div>',
        '<h1></h1>',
    '</div>
].join('');
  • 当函数调用时,如果有一个或以上参数跨越多行,应当每一个参数独立一样。
    • 这通常出现在匿名函数或者对象初始化作为参数时,如setTimeout等
// good
setTimeout(
    function () {
        console.log('setTimeout');
    },
    300
);
// bad
setTimeout(function() {
    console.log('setTimeout');
}, 1000);

链式操作

  • 链式调用较长时采用缩进进行调整
  • 三元运算符由三部分组成,因此其换行应当对于每个部分的长度不同,形成不同的情况
// good
$('#item)
    .find('.select')
    .eq(1)
    .end();
var result = isTrue
    ? resultA
    : resultB;

// 数组和对象初始化调用,严格按照每个对象的{}在独立一行的书写风格
var array = [
    {},
    {}
];
var array = [
    {
        // code
    },
    {
        // code
    }
];

代码分号

  • 不得省略语句结束的分号
  • 在if /else / for / do / while语句中,即使只有一行,也不得省略{}
  • 函数定义结束不允许添加分号
// good
var name = '';
if (true) {
    name = '';
}
function test() {}
// bad
var name = ''
if (true) name = '';
function test() {};

命名

  • 变量 使用 camel 命名法
  • 常量 使用 全部字母大写,单词间下划线分割 命名法
  • 函数 使用 Camel 命名法
  • 类 使用 Pascal 命名法
  • 函数参数 使用 Camel 命名法
  • 类方法属性 使用 Camel 命名法
  • 类名 使用名词
  • 函数名 使用动宾短语
  • boolean类型变量使用is或has开头
  • 变量,函数在使用前必须先定义
  • 每个var,let,const建议只定义一个变量
// good
let userName = '';
let isTrue = true;
const PI = 3.14;
const USER_NAME = '';
function getStyle() {}
class Test {}

// good
var name = ''

// bad
name = '';
  • 尽量使用 ===,!==,不适用== ,!=,仅当判断null或undefined时允许使用==null

循环

  • 不要在循环体中包含函数表达式,事先将函数提取到循环体外。
  • 对有序集合遍历时,缓存length
    • 虽然浏览器都对数组长度进行了缓存,但对于一些宿主对象和老旧浏览器的数组对象,在每次length访问时会动态计算元素个数,此时缓存length能有效提高程序性能
// good
for (var i = 0, len = elements.length; i < len; i++) {

}

类型

类型检测

  • 类型检测优先使用typeof。对象类型检测使用instanceof。 null或undefined使用==null
typeof variable === 'string'; // string
typeof variable === 'number'; // number
typeof variable === 'boolean'; // boolean
typeof variable === 'function'; // Function
typeof variable === 'object'; // Object

variable instanceof RegExp; // RegExp;
variable instanceof Array; // Array

variable === null; // null
variable === 'undefined'; // undefined;
variable == null; // null or undefined;

类型转换

  • 转换为string时,使用+’’。
// good
num + '';
  • 转换为number时,通常使用+。
// good
+str;
// bad
Number(str);
  • string 转换为 number ,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt。
  • 使用 parseInt 时,必须制定进制
// good
var width = '200px';
parseInt(width, 10);
// bad
parseInt(width);
  • number 去除小数点, 使用Math.floor / Math.round / Math.ceil,不使用 parseInt
// good
var num = 3.14;
Math.ceil(num);
// bad
parseInt(num, 10);

闭包

  • 建议在适当的时候将闭包内大对象设置为null

    闭包会阻止一些变量的垃圾回收,对于较老旧的JavaScript引擎,可能导致外部所有变量均无法回收。

    以下内容会影响到闭包内变量的回收:

    • 嵌套的函数中是否有使用的变量
    • 嵌套的函数中是否有 直接调用eval
    • 是否使用with表达式

    Chakra、V8和SpiderMonkey将受以上因素的影响,表现出不尽相同又较相似的回收策略,而JScript.dll和Carakan则完全没有这方面的优化,会完全整个LexicalEnvironment中的所有变量绑定,造成一定的内存消耗。

    如果有非常庞大的对象,切预计会在老旧的引擎中执行,则使用闭包时,注意将闭包不需要的对象设置为空引用。

注释

  • 单行注释// 后跟一个空格
  • 多行注释 /* */ ,尽量避免使用,尽量使用单行注释代替
  • 文档注释 /** */形式
  • 文档注释前必须空一行

注释类型说明

基本类型使用小写(number, string, (boolean),引用类型使用大写(Object, Function, Array, Date, RegExp…)

类型 语法 解释
String {string}
Number {number}
Boolean {boolean}
Object {Object}
Function {Function}
RegExp {RegExp}
Array {Array}
Date {Date}
单一类型集合 {Array}
多类型 {number/boolean} 可能时number类型也可能时boolean类型
任意类型 {*} 任意类型

文件注释

// 文件注释
/**
 * @file describe the file
 * @author wjf
 */

// 命名空间
/**
 * @namespace
 */

/**
 * 描述
 *
 * @class 类名称
 * @extends dev
 */

函数注释,方法注释

/**
 * 函数描述
 *
 * @param {string} name 参数1
 * @param {Object} param 参数2
 * @param {string} param.name 参数2描述
 * @return {Object} 返回值描述
 */

事件注释

/**
 * 事件描述
 *
 * @event select#change
 * @param {} params
 */

模块注释

/**
 * module description
 *
 * @module
 * @exports {number}
 * @exports {string}
 */

其他注释标识符

/**
 * @file 文件
 * @namespace 命名空间
 * @module regexp 模块
 * @constructor 构造函数声明注释
 * @param {string} params 参数注释
 * @class 类
 * @extends dev 继承
 * @overview 对当前代码文件的描述
 * @copyright 版权信息
 * @author wjf 代码作者信息
 * @version 1.2.2 版本信息
 * @throws {string} 抛出异常
 * @createDate 2019 创建时间
 * @example http() 示例展示,使用方法
 * @return {string} 返回值
 */