javascript语言编码规范
javascript语言编码规范
命名
- [强制] 变量 使用 Camel命名法。
var loadingModules = {};
- [强制] 常量 使用 全部字母大写,单词间下划线分隔 的命名方式
var HTML_ENTITY = {};
- [强制] 函数 使用 Camel命名法,可使用常见动词约定
- can 判断是否可执行某个动作,函数返回一个布尔值。true:可执行;false:不可执行
- has 判断是否含有某个值, 函数返回一个布尔值。- true:含有此值;false:不含有此值
- is: 判断是否为某个值,函数返回一个布尔值。true:为某个值;false:不为某个值
- get: 获取某个之,函数返回一个非布尔值
- set: 设置某个值,无返回值、返回是否设置成功或者返回链式对象 load 加载某些数据,无返回值或者返回是否加载完成的结果
- [强制] 函数的 参数 使用 Camel命名法。
function hear(theBells) {
}
- [强制] 类 使用 Pascal命名法
function TextNode(options) {
}
-
[强制] 枚举变量 使用 Pascal命名法,枚举的属性 使用 全部字母大写,单词间下划线分隔 的命名方式。
var TargetState = { READING: 1, READED: 2, APPLIED: 3, READY: 4 };
-
[强制] 由多个单词组成的缩写词,在命名中,根据当前命名法和出现的位置,所有字母的大小写与首字母的大小写保持一致
function XMLParser() { } function insertHTML(element, html) { } var httpRequest = new HTTPRequest();
-
[强制] 类名 使用 名词
function Engine(options) { }
-
[建议] boolean 类型的变量使用 is 或 has 开头。
var isReady = false; var hasMoreCommands = false;
代码风格
- 导出的默认函数使用驼峰命名、文件名与函数完全一致。
- 导出单例、函数库、空对象时使用帕斯卡式命名(帕斯卡式命名法是在命名的时候将首字母大写, 如: DisplayInfo
- if / else / for / while / function / switch / do / try / catch / finally 关键字后,必须有一个空格
// good
if (condition) {
}
while (condition) {
}
(function () {
})();
// bad
if(condition) {
}
while(condition) {
}
(function() {
})();
- 在对象创建时,属性中的 : 之后必须有空格,: 之前不允许有空格
示例:
// good
var obj = {
a: 1,
b: 2,
c: 3
};
// bad
var obj = {
a : 1,
b:2,
c :3
};
- 函数声明、具名函数表达式、函数调用中,函数名和 ( 之间不允许有空格。
// good
function funcName() {
}
var funcName = function funcName() {
};
funcName();
// bad
function funcName () {
}
var funcName = function funcName () {
};
funcName ();
- 逗号写在行尾, 并且增加结尾的逗号。
- 使用分号, 以分号作为语句的结束符
# good
const obj = {
firstName: 'Dana',
lastName: Scally',
};
# bad
const obj = {
firstName: 'Dana',
lastName: 'Scally'
};
- 使用大括号包裹所有的多行代码块
- 如果通过if和else使用多行代码块, 把else放在if代码块关闭括号的同一行。
if(arg) {
return arg;
} else {
return false;
}
- 不要使用通配符 *的import
- 如果你的文件只输出一个类, 那你的文件名必须和类名完全保持一致。
import CheckBox from './CheckBox';
类型和变量
- 变量必须显式声明作用域
- var => 用于声明全局变量或函数级变量
- let => 用于声明块级的局部变量
- const => 声明块级域的只读局部变量
- 尽量对所有的引用使用const, 不要使用var。 如果你一定需要使用可变动的引用,使用let代替var
- 将所有的const和let分组
- 在需要的地方给变量赋值
// good
const a = 1;
const b = 2;
let count = 1;
if (true) {
count += 1;
}
// bad
var a = 1;
var b = 2;
var count = 1;
if (true) {
count += 1;
}
- [强制] 每个 var 只能声明一个变量。
一个 var 声明多个变量,容易导致较长的行长度,并且在修改时容易造成逗号和分号的混淆
// good
var hangModules = [];
var missModules = [];
var visited = {};
// bad
var hangModules = [],
missModules = [],
visited = {};
- 变量必须 即用即声明,不得在函数或其它形式的代码块起始位置统一声明所有变量。
变量声明与使用的距离越远,出现的跨度越大,代码的阅读与维护成本越高。虽然JavaScript的变量是函数作用域,还是应该根据编程中的意图,缩小变量出现的距离空间。
条件
- 在 Equality Expression 中使用类型严格的 ===。仅当判断 null 或 undefined 时,允许使用 == null。
使用 === 可以避免等于判断中隐式的类型转换。
// good
if (age === 30) {
// ......
}
// bad
if (age == 30) {
// ......
}
- 尽可能使用简洁的表达式。
// 字符串为空
// 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') {
// ......
}
- [建议] 对于相同变量或表达式的多值条件,用 switch 代替 if。
// 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。
/ good
function getName() {
if (name) {
return name;
}
return 'unnamed';
}
// bad
function getName() {
if (name) {
return name;
}
else {
return 'unnamed';
}
}
循环
- [建议] 不要在循环体中包含函数表达式,事先将函数提取到循环体外。
循环体中的函数表达式,运行过程中会生成循环次数个函数对象
// 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 () {});
}
- [建议] 对循环内多次使用的不变值,在循环外用变量缓存
// good
var width = wrap.offsetWidth + 'px';
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
element.style.width = width;
// ......
}
// bad
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
element.style.width = wrap.offsetWidth + 'px';
// ......
}
- [建议] 对有序集合进行遍历时,缓存 length。
虽然现代浏览器都对数组长度进行了缓存,但对于一些宿主对象和老旧浏览器的数组对象,在每次 length 访问时会动态计算元素个数,此时缓存 length 能有效提高程序性能。
for (var i = 0, len = elements.length; i < len; i++) {
var element = elements[i];
// ......
}
- [建议] 对有序集合进行顺序无关的遍历时,使用逆序遍历。
逆序遍历可以节省变量,代码比较优化。
var len = elements.length;
while (len--) {
var element = elements[len];
// ......
}
类型
类型检测
- [建议] 类型检测优先使用 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 时,使用 + ''。
// good
num + '';
// bad
new String(num);
num.toString();
String(num);
- [建议] 转换成 number 时,通常使用 +。
- string 转换成 number,要转换的字符串结尾包含非数字并期望忽略时,使用 parseInt。
let width = '200px';
parseInt(width, 10);
- [强制] 使用 parseInt 时,必须指定进制。
// good
parseInt(str, 10);
// bad
parseInt(str);
- [建议] 转换成 boolean 时,使用 !!。
let num = 3.14;
!!num;
- [建议] number 去除小数点,使用 Math.floor / Math.round / Math.ceil,不使用 parseInt。
// good
let num = 3.14;
Math.ceil(num);
// bad
let num = 3.14;
parseInt(num, 10);
对象和引用
- [强制] 使用对象字面量 {} 创建新 Object。
// good
var obj = {};
// bad
var obj = new Object();
- [建议] 对象创建时,如果一个对象的所有 属性 均可以不添加引号,建议所有 属性 不添加引号。
var info = {
name: 'someone',
age: 28
};
- [建议] 对象创建时,如果任何一个 属性 需要添加引号,则所有 属性 建议添加 '。
如果属性不符合 Identifier 和 NumberLiteral 的形式,就需要以 StringLiteral 的形式提供。
# good
var info = {
'name': 'someone',
'age': 28,
'more-info': '...'
};
# bad
var info = {
name: 'someone',
age: 28,
'more-info': '...'
};
- 属性访问时,尽量使用 .。
通常在 JavaScript 中声明的对象,属性命名是使用 Camel 命名法,用 . 来访问更清晰简洁。部分特殊的属性(比如来自后端的 JSON ),可能采用不寻常的命名方式,可以通过 [expr] 方式访问。
info.age;
info['more-info'];
- 使用对象方法的简写
# good
let name = "zhangsan"
const obj = {
name
}
# bad
let name = "zhangsan"
const obj = {
name:name
}
- 访问外部对象时, 需要先判断对象是否为空
String
- [强制] 字符串开头和结束使用单引号 '。
1.输入单引号不需要按住 shift,方便输入。
2.实际使用中,字符串经常用来拼接 HTML。为方便 HTML 中包含双引号而不需要转义写法。
var str = '我是一个字符串';
var html = '<div class="cls">拼接HTML可以省去双引号转义</div>';
- 长度超过80的字符串应该使用字符串连接换行。
- 构建字符串时, 使用字符串模板而不是字符串连接。
function sayHi(name) {
return `How are you, ${name}`;
}
数组
- [强制] 使用数组字面量 [] 创建新数组,除非想要创建的是指定长度的数组。
// good
var arr = [];
// bad
var arr = new Array();
- [强制] 遍历数组不使用 for in。
数组对象可能存在数字以外的属性, 这种情况下 for in 不会得到正确结果。
-
[建议] 不因为性能的原因自己实现数组排序功能,尽量使用数组的 sort 方法。
自己实现的常规排序算法,在性能上并不优于数组默认的 sort 方法。以下两种场景可以自己实现排序:需要稳定的排序算法,达到严格一致的排序结果。
数据特点鲜明,适合使用桶排。
-
[建议] 清空数组使用 .length = 0。
-
使用扩展运算符 ... 复制数组
扩展运算符可以减少赋值语句的使用, 或者减少通过下标访问数组或对象的方式, 使用代码更加简洁优雅, 可读性更佳
```
# good
const itemsCopy = [...items];
# bad
const len = items.length;
const itemsCopy = [];
let i;
for(i=0; i<len; i++) {
itemsCopy[i] = items[i];
}
```
函数
- [建议] 一个函数的长度控制在 50 行以内。
- 一个函数的参数控制在 6 个以内
除去不定长参数以外,函数具备不同逻辑意义的参数建议控制在 6 个以内,过多参数会导致维护难度增大。
- 通过 options 参数传递非数据输入型参数。
有些函数的参数并不是作为算法的输入,而是对算法的某些分支条件判断之用,此类参数建议通过一个 options 参数传递。
#good
/**
* 移除某个元素
*
* @param {Node} element 需要移除的元素
* @param {Object} options 相关的逻辑配置
* @param {boolean} options.removeEventListeners 是否同时将所有注册在元素上的事件移除
*/
function removeElement(element, options) {
element.parent.removeChild(element);
if (options.removeEventListeners) {
element.clearEventListeners();
}
}
# bad
/**
* 移除某个元素
*
* @param {Node} element 需要移除的元素
* @param {boolean} removeEventListeners 是否同时将所有注册在元素上的事件移除
*/
function removeElement(element, removeEventListeners) {
element.parent.removeChild(element);
if (removeEventListeners) {
element.clearEventListeners();
}
}
- [建议] 空函数不使用 new Function() 的形式。
var emptyFunction = function () {};
箭头函数
- 别保存this的引用, 使用箭头函数或Function.bind
- 当你必须使用函数表达式(或传递一个匿名函数)时, 使用箭头函数
# good
[1, 2, 3].map( (x) => {
return x * x;
});
# bad
[1, 2, 3].map(function(x) {
return x * x;
});
- 如果一个函数适用一行写出并且只有一个参数, 那就把花括号、圆括号和return都省略掉, 如果不是, 那就不要省略。
```
[1, 2, 3].map( x => x * x;);
```
解构
- 使用解构存取和使用多属性对象。
说明:
ES6允许按照一定的模式, 从数组和对象中提取值、对变量进行赋值, 这称之为解构, 解构赋值避免了临时变量或对象, 给JavaScript书写带来了很大的便利性, 同时也提高了代码的可读性。
# good
let user = {
firstName: "Jack",
lastName: "Ma",
};
function getFullName({firstName,lastName}){
return `${user.firstName} ${user.lastName}`;
}
# bad
function getFullName (user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
- 需要回传多个值时, 使用对象解构, 而不是数组解构
对象解构在增加属性或改变排序时, 无需改变调用时的位置。