每个人都有固定的一套编码习惯,但在团队协作过程中,则需要每个人都遵守统一的编码约定和编程方法。
编程风格
-
基本的格式化
1、缩进层级
(1)不好的习惯if( con == ''){ console.log('是不是分不清层级')} else{ console.log('没有主次')}
(2)好的习惯
if( con == ''){ console.log('层级很清晰'); } else{ console.log('简单明了'); }
2、语句结尾
(1)不好的习惯function getVal(){ return { title:'jialin', age:23 } } //分析器会将他理解为 function getVal(){ return; //这样的return返回的是undefined,我们想要的是返回数据对象 { title:'jialin', age:23 } }
(2)好的习惯
function getVal(){ return { //将return和花括号放置一行 title:'jialin', age:23 } }
3、变量和函数的命名
- 采取小驼峰命名,如:getName,setVal...
- 命名有意义,体现出类型,如:count、length、size表示数字类型,name、title等表示字符串类型。
4、null
- null是一个特殊值,不要将它和undefined高混淆,undefined派生于null,但它们的数据类型不相等
适用于null的场景
- 用来初始化一个变量 - 用来和一个已经初始化的变量比较 - 当函数的参数期望是对象时,用作参数传入 - 当函数的返回值期望是对象时,用作返回值传出
不适于null
- 不要使用null来检测是否传入了某个参数 - 不要使用null来检测一个未初始化的变量
理解null的最好方式将他当做占位符,对于全局维护性来说至关重要
5、undefined
//不好的写法
var val;
console.log(typeof val); //undefined
console.log(typeof name); //undefined 会报错, 返回值和typeof容易混淆
以下是我们老大分享的代码规范,在这里分享给你们
js代码规范
文档
JavaScript 文件使用无 BOM 的 UTF-8 编码。
在文件结尾处,保留一个空行。
使用 2 个空格做为一个缩进层级,不允许使用 4 个空格 或 tab 字符。
每个独立语句结束后必须换行。每行不得超过 120 个字符。
运算符处换行时,运算符必须在新行的行首。
// good
if (user.isAuthenticated()
&& user.isInRole('admin')
&& user.hasAuthority('add-admin')
|| user.hasAuthority('delete-admin')
) {
// Code
}
var result = number1 + number2 + number3
+ number4 + number5;
// bad
if (user.isAuthenticated() &&
user.isInRole('admin') &&
user.hasAuthority('add-admin') ||
user.hasAuthority('delete-admin')) {
// Code
}
var result = number1 + number2 + number3 +
number4 + number5;
在函数声明、函数表达式、函数调用、对象创建、数组创建、for语句等场景中,不允许在 , 或 ; 前换行。
// good
var obj = {
a: 1,
b: 2,
c: 3
};
foo(
aVeryVeryLongArgument,
anotherVeryLongArgument,
callback
);
// bad
var obj = {
a: 1
, b: 2
, c: 3
};
foo(
aVeryVeryLongArgument
, anotherVeryLongArgument
, callback
);
不同行为或逻辑的语句集,使用空行隔开,更易阅读。
当参数过多时,将每个参数独立写在一行上,并将结束的右括号 ) 独立一行。所有参数必须增加一个缩进。
foo(
aVeryVeryLongArgument,
anotherVeryLongArgument,
callback
);
也可以按逻辑对参数进行组合。
比如angularjs的服务注入,可以将框架提供的服务、自定义服务、常量、提供器分开。
function run(
$log, $rootScope, $cookies, // 框架内提供
serverConfig, CONFIG, // 提供器、常量
common, sgCommon, // 自定义服务
);
三元运算符由3部分组成,因此其换行应当根据每个部分的长度不同,形成不同的情况。
var result = thisIsAVeryVeryLongCondition
? resultA : resultB;
var result = condition
? thisIsAVeryVeryLongResult
: resultB;
对于 if...else...、try...catch...finally 等语句,推荐使用在 } 号后添加一个换行 的风格,使代码层次结构更清晰,阅读性更好。
if (condition) {
// some statements;
}
else {
// some statements;
}
try {
// some statements;
}
catch (ex) {
// some statements;
}
不得省略语句结束的分号。
在 if / else / for / do / while 语句中,即使只有一行,也不得省略块 {...}。
// good
if (condition) {
callFunc();
}
// bad
if (condition) callFunc()
if (condition)
callFunc()
命名
变量 使用 Camel命名法。
var loadingModules = {};
常量 使用 全部字母大写,单词间下划线分隔 的命名方式。
var HTML_ENTITY = {};
函数 使用 Camel命名法。
function stringFormat(source) {
}
类 使用 Pascal命名法。
function TextNode(options) {
}
枚举变量 使用 Pascal命名法,枚举的属性 使用 全部字母大写,单词间下划线分隔 的命名方式。
var TargetState = {
READING: 1,
READED: 2,
APPLIED: 3,
READY: 4
};
命名空间 使用 Camel命名法。
equipments.heavyWeapons = {};
类名 使用 名词。
函数名 使用 动宾短语。
function getStyle(element) {
}
boolean 类型的变量使用 is 或 has 开头。
Promise对象 用 动宾短语的进行时 表达。
注释
代码细节注释全部使用行注释,不可使用这样的/*...*/多行注释
为了便于代码阅读和自文档化,以下内容必须包含以 /**...*/ 形式的块注释。
- 文件
- namespace
- 类
- 函数或方法
- 类属性
- 事件
- 全局变量
- 常量
注释中类型说明格式以{
开始, 以}
结束。
常用类型如:{string}, {number}, {boolean}, {Object}, {Function}, {RegExp}, {Array}, {Date}。
/**
* 函数描述
*
* @param {string} p1 参数1的说明
* @param {string} p2 参数2的说明,比较长
* 那就换行了.
* @param {number=} p3 参数3的说明(可选)
* @return {Object} 返回值描述
*/
类型定义 | 语法示例 | 解释 |
---|---|---|
String | {string} | -- |
Number | {number} | -- |
Boolean | {boolean} | -- |
Object | {Object} | -- |
Function | {Function} | -- |
RegExp | {RegExp} | -- |
Array | {Array} | -- |
Date | {Date} | -- |
单一类型集合 | {Array.<string>} | string 类型的数组 |
多类型 | {(number|boolean)} | 可能是 number 类型, 也可能是 boolean 类型 |
允许为null | {?number} | 可能是 number, 也可能是 null |
不允许为null | {!Object} | Object 类型, 但不是 null |
Function类型 | {function(number, boolean)} | 函数, 形参类型 |
Function带返回值 | {function(number, boolean):string} | 函数, 形参, 返回值类型 |
参数可选 | @param {string=} name | 可选参数, =为类型后缀 |
可变参数 | @param {...number} args | 变长参数, ...为类型前缀 |
任意类型 | {*} | 任意类型 |
可选任意类型 | @param {*=} name | 可选参数,类型不限 |
可变任意类型 | @param {...*} args | 变长参数,类型不限 |
文件注释
注释添加作者一项
/**
* @file Describe the file
* @author xiaozhao@domain.com
*/
命名空间注释
/**
* 描述
* @namespace
*/
var util = {};
使用 @class
标记类或构造函数。
/**
* 描述
*
* @class
*/
function Developer() {
// constructor body
}
使用 @extends
标记类的继承信息。
/**
* 描述
*
* @class
* @extends Developer
*/
function UserInfoController (){
BaseController.call(this);
this.init();
}
函数/方法注释必须包含函数说明,有参数和返回值时必须使用注释标识。
参数和返回值注释必须包含类型信息和说明。
/**
* 函数描述
*
* @param {string} p1 参数1的说明
* @param {string} p2 参数2的说明,比较长
* 那就换行了.
* @param {number=} p3 参数3的说明(可选)
* @return {Object} 返回值描述
*/
function foo(p1, p2, p3) {
var p3 = p3 || 10;
return {
p1: p1,
p2: p2,
p3: p3
};
}
对 Object 中各项的描述, 必须使用 @param
标识。
/**
* 函数描述
*
* @param {Object} option 参数描述
* @param {string} option.url option项描述
* @param {string=} option.method option项描述,可选参数
*/
function foo(option) {
// TODO
}
重写父类方法时, 应当添加 @override
标识。如果重写的形参个数、类型、顺序和返回值类型均未发生变化,可省略 @param
、@return
,仅用 @override
标识,否则仍应作完整注释。
必须使用 @event
标识事件,事件参数的标识与方法描述的参数标识相同。
/**
* 值变更时触发
*
* @event
* @param {Object} e e描述
* @param {string} e.before before描述
* @param {string} e.after after描述
*/
onchange: function (e) {
}
在会广播事件的函数前使用 @fires
标识广播的事件,在广播事件代码前使用 @event
标识事件。
常量注释
常量必须使用 @const
标记,并包含说明和类型信息。
/**
* 常量说明
*
* @const
* @type {string}
*/
var REQUEST_URL = 'myurl';
变量
变量在使用前必须通过 var
定义,每个 var
只能声明一个变量。变量必须 即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量。
在 Equality Expression 中使用类型严格的 ===
。仅当判断 null 或 undefined 时,允许使用 == null
。
尽可能使用简洁的表达式。
// 字符串为空
// 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') {
// ......
}
不要在循环体中包含函数表达式,事先将函数提取到循环体外。
// 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 () {});
}
对循环内多次使用的不变值,在循环外用变量缓存。
类型检测优先使用 typeof
。对象类型检测使用 instanceof
。null
或 undefined
的检测使用 == null
。
// string
typeof variable === 'string'
// number
typeof variable === 'number'
// boolean
typeof variable === 'boolean'
// Function
typeof variable === 'function'
// Object
typeof variable === 'object'
// RegExp
variable instanceof RegExp
// Array
variable instanceof Array
// null
variable === null
// null or undefined
variable == null
// undefined
typeof variable === 'undefined'
类型转换
转换成 string
时,使用 + ''
。
转换成 number
时,通常使用 +
。
string
转换成 number
,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt
。
var width = '200px';
parseInt(width, 10);
转换成 boolean
时,使用 !!
。
number
去除小数点,使用 Math.floor / Math.round / Math.ceil
,不使用 parseInt
。
使用 数组
或 +
拼接字符串。
for in
遍历对象时, 使用 hasOwnProperty
过滤掉原型中的属性。
遍历数组不使用 for in
。
不会被调用的依赖模块,在文件开始处统一 require
。
网络请求
在懒加载、调用接口获取数据时,需要考虑长时间网络延迟的情况下显示加载动画。