1.基本规范
命名规范
- camelCase(小驼峰命名,e.g. userInfo)
- PascalCase(大驼峰命名,e.g. UserInfo)
- kebab-case(短横线连接式,e.g. user-info)
- snake_case(下划线连接式,e.g. user_info)
项目命名
一律采用小写,以下划线分隔,以"k12_项目名称"形式创建项目。
html命名
一律采用小写,以下划线分隔(除index文件外)。
css文件命名
一律采用小写,以下划线分隔 (除index文件外)。
2.HTML规范
语法标准
- 缩进使用 tab(2 个空格);
- 嵌套的节点应该缩进;
- 在属性上,使用双引号,不要使用单引号;
- 属性名全小写,用中划线(-)做分隔符;
- 要在自动闭合标签结尾处使用斜线;
- 不要省略可选的结束标签(例如,
- 或 )。
<!DOCTYPE html>
<html>
<head>
<title>Page title</title>
</head>
<body>
<img src="images/image.png" alt="Image" />
<!-- 属性名全小写,用中划线(-)做分隔符 -->
<h1 class="hello-world">Hello, world!</h1>
</body>
</html>
doctype
为每个 HTML 页面的第一行添加 standards mode(标准模式) 声明,这样能够确保在每个浏览器中拥有一致的展现。
IE 兼容模式
IE 支持通过特定的 标签来确定绘制当前页面所应该采用的 IE 版本。除非有强烈的特殊需求,否则最好是设置为 edge mode,从而通知 IE 采用其所支持的最新的绘制模式。
<meta http-equiv="x-ua-compatible" content="ie=edge">
规定字符串编码
通过声明一个明确的字符编码,让浏览器轻松、快速的确定适合网页内容的渲染方式,通常指定为’UTF-8’。
减少标签数
减少无用标签,精简页面代码。
<!-- bad -->
<span class="avatar">
<img src="..." />
</span>
<!-- good -->
<img class="avatar" src="..." />
语义化标签
html 的标签能使用语义化的,尽量使用语义化标签,避免一个页面都是 div 或者 p 标签。
<!-- bad -->
<div>
<p></p>
</div>
<!-- good -->
<header></header>
<footer></footer>
属性顺序
HTML 属性应当按照以下给出的顺序依次排列,确保代码的易读性。class 用于标识高度可复用组件,因此应该排在首位。id 用于标识具体组件,应当谨慎使用(例如,页面内的书签),因此排在第二位
- class
- id, name
- data-*
- src, for, type, href, value
- title, alt
- role, aria-*
3.CSS规范
语法标准
- 用两个空格来代替制表符(tab)。
- 为选择器分组时,将单独的选择器单独放在一行。
- 为了代码的易读性,在每个声明块的左花括号前添加一个空格。
- 声明块的右花括号应当单独成行。
- 每条声明语句的 : 后应该插入一个空格。
- 为了获得更准确的错误报告,每条声明都应该独占一行。
- 所有声明语句都应当以分号结尾。
- 对于以逗号分隔的属性值,每个逗号后面都应该插入一个空格(例如,box-shadow)。
- 不要在 rgb()、rgba()、hsl()、hsla() 或 rect() 值的内部的逗号后面插入空格。这样利于从多个属性值(既加逗号也加空格)中区分多个颜色值(只加逗号,不加空格)。
- 对于属性值或颜色参数,省略小于 1 的小数前面的 0 (例如,.5 代替 0.5;-.5px 代替 -0.5px)。
- 十六进制值应该全部小写,例如,#fff。在扫描文档时,小写字符易于分辨,因为他们的形式更易于区分。
- 尽量使用简写形式的十六进制值,例如,用 #fff 代替 #ffffff。
- 为选择器中的属性添加双引号,例如,input[type=“text”]。只有在某些情况下是可选的,但是,为了代码的一致性,建议都加上双引号。
- 避免为 0 值指定单位,例如,用 margin: 0; 代替 margin: 0px;。
/* bad */
.selector, .selector-secondary, .selector[type=text] {
padding:15px;
margin:0px 0px 15px;
background-color:rgba(0, 0, 0, 0.5);
box-shadow:0px 1px 2px #CCC,inset 0 1px 0 #FFFFFF
}
/* good */
.selector,
.selector-secondary,
.selector[type="text"] {
padding: 15px;
margin-bottom: 15px;
background-color: rgba(0,0,0,.5);
box-shadow: 0 1px 2px #ccc, inset 0 1px 0 #fff;
}
命名
类名使用小写字母,以中划线分割;id采用驼峰式命名
/* class */
.element-content {
...;
}
/* id */
#myDialog {
...;
}
3.JavaScript规范
语法规范
- 缩进使用 tab(2 个空格);
- 嵌套的节点应该缩进;
变量
- 避免使用 var声明变量,使用 const 定义只读变量,使用let定义可读写变量。
- 把const变量与let变量分开存放
- 不要链式变量赋值
- 避免使用不必要的递增和递减(++,–)。
- 避免在赋值语句 = 前后换行。如果你的代码违反了 max-len, 使用括号包裹。
// bad
const foo =
superLongLongLongLongLongLongLongLongFunctionName();
// bad
const foo
= 'superLongLongLongLongLongLongLongLongString';
// good
const foo = (
superLongLongLongLongLongLongLongLongFunctionName()
);
// good
const foo = 'superLongLongLongLongLongLongLongLongString';
对象
- 使用字面语法来创建对象
- 在创建具有动态属性名称的对象时使用计算属性名
function getKey(k) {
return `a key named ${k}`;
}
// bad
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
- 属性名与属性值相同时,使用缩写
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
- 更喜欢对象扩展操作符,而不是用 Object.assign 浅拷贝一个对象。 使用对象的 rest 操作符来获得一个具有某些属性的新对象。
// very bad
const original = { a: 1, b: 2 };
const copy = Object.assign(original, { c: 3 }); // 变异的 `original` ಠ_ಠ
delete copy.a; // 这....
// bad
const original = { a: 1, b: 2 };
const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }
// good
const original = { a: 1, b: 2 };
const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }
const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
数组
- 使用字面语法创建数组。
- 使用数组展开方法 … 来拷贝数组。
- 将一个类数组对象转换成一个数组, 使用展开方法 … 代替 Array.from。
const foo = document.querySelectorAll('.foo');
// good
const nodes = Array.from(foo);
// best
const nodes = [...foo];
- 对于对迭代器的映射,使用 Array.from 替代展开方法 … , 因为它避免了创建中间数组。
// bad
const baz = [...foo].map(bar);
// good
const baz = Array.from(foo, bar);
- 如果数组有多行,则在开始的时候换行,然后在结束的时候换行。
解构
- 在访问和使用对象的多个属性的时候使用对象的解构。
// bad
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
return `${firstName} ${lastName}`;
}
// good
function getFullName(user) {
const { firstName, lastName } = user;
return `${firstName} ${lastName}`;
}
// best
function getFullName({ firstName, lastName }) {
return `${firstName} ${lastName}`;
}
字符
- 使用单引号 ‘’ 定义字符串。
- 使行超过100个字符的字符串不应使用字符串连接跨多行写入。
- 当以编程模式构建字符串时,使用字符串模板代替字符串拼接。
- 不要在字符串上使用 eval()。
方法
- 使用命名的函数表达式代替函数声明。
// bad
function foo() {
// ...
}
// bad
const foo = function () {
// ...
};
// good
// 从变量引用调用中区分的词汇名称
const short = function longUniqueMoreDescriptiveLexicalFoo() {
// ...
};
- 永远不要定义一个参数为 arguments。
- 不要使用 arguments, 选择使用 rest 语法 … 代替
// bad
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
- 使用默认的参数语法,而不是改变函数参数。
// really bad
function handleThings(opts) {
// No! We shouldn’t mutate function arguments.
// Double bad: if opts is falsy it'll be set to an object which may
// be what you want but it can introduce subtle bugs.
opts = opts || {};
// ...
}
// still bad
function handleThings(opts) {
if (opts === void 0) {
opts = {};
}
// ...
}
// good
function handleThings(opts = {}) {
// ...
}
- 总是把默认参数放在最后。
- 不要再赋值参数。
// bad
function f1(a) {
a = 1;
// ...
}
function f2(a) {
if (!a) { a = 1; }
// ...
}
// good
function f3(a) {
const b = a || 1;
// ...
}
function f4(a = 1) {
// ...
}
- 具有多行签名或者调用的函数应该像本指南中的其他多行列表一样缩进:在一行上只有一个条目,并且每个条目最后加上逗号。
// bad
function foo(bar,
baz,
quux) {
// ...
}
// good
function foo(
bar,
baz,
quux,
) {
// ...
}
// bad
console.log(foo,
bar,
baz);
// good
console.log(
foo,
bar,
baz,
);
箭头函数
- 当你必须使用匿名函数时 (当传递内联函数时), 使用箭头函数。
// bad
[1, 2, 3].map(function (x) {
const y = x + 1;
return x * y;
});
// good
[1, 2, 3].map((x) => {
const y = x + 1;
return x * y;
});
- 如果函数体包含一个单独的语句,返回一个没有副作用的 expression , 省略括号并使用隐式返回。否则,保留括号并使用 return 语句。
// bad
[1, 2, 3].map(number => {
const nextNumber = number + 1;
`A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map((number) => {
const nextNumber = number + 1;
return `A string containing the ${nextNumber}.`;
});
// good
[1, 2, 3].map((number, index) => ({
[index]: number,
}));
// 没有副作用的隐式返回
function foo(callback) {
const val = callback();
if (val === true) {
// 如果回调返回 true 执行
}
}
let bool = false;
// bad
foo(() => bool = true);
// good
foo(() => {
bool = true;
});
类和构造器
- 尽量使用 class. 避免直接操作 prototype 。
// bad
function Queue(contents = []) {
this.queue = [...contents];
}
Queue.prototype.pop = function () {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
};
// good
class Queue {
constructor(contents = []) {
this.queue = [...contents];
}
pop() {
const value = this.queue[0];
this.queue.splice(0, 1);
return value;
}
}
- 使用 extends 来扩展继承。
// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function () {
return this.queue[0];
};
// good
class PeekableQueue extends Queue {
peek() {
return this.queue[0];
}
}
- 如果没有指定类,则类具有默认的构造器。 一个空的构造器或是一个代表父类的函数是没有必要的。
class Jedi {
constructor() {}
getName() {
return this.name;
}
}
// bad
class Rey extends Jedi {
constructor(...args) {
super(...args);
}
}
// good
class Rey extends Jedi {
constructor(...args) {
super(...args);
this.name = 'Rey';
}
}
- 避免定义重复的类成员。
模块
- 建议不要使用通配符导入。除非没有一个单独的默认导出。
- 不要直接从导入导出。
// bad
// filename es6.js
export { es6 as default } from './AirbnbStyleGuide';
// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;
- 只从一个路径导入所有需要的东西
// bad
import foo from 'foo';
// … 其他导入 … //
import { named1, named2 } from 'foo';
// good
import foo, { named1, named2 } from 'foo';
// good
import foo, {
named1,
named2,
} from 'foo';
- 不要导出可变的引用
- 将所有的 imports 语句放在所有非导入语句的上边。
- 多行导入应该像多行数组和对象一样缩进。
// bad
import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';
// good
import {
longNameA,
longNameB,
longNameC,
longNameD,
longNameE,
} from 'path';
属性
- 访问属性时使用点符号。使用变量访问属性时,使用 []表示法。
const luke = {
jedi: true,
age: 28,
};
// bad
const isJedi = luke['jedi'];
// good
const isJedi = luke.jedi;
const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');
- 计算指数时,可以使用 ** 运算符。
// bad
const binary = Math.pow(2, 10);
// good
const binary = 2 ** 10;
块
- 当有多行代码块的时候,使用大括号包裹。
// bad
if (test)
return false;
// good
if (test) return false;
// good
if (test) {
return false;
}
// bad
function foo() { return false; }
// good
function bar() {
return false;
}
- 如果你使用的是 if 和 else 的多行代码块,则将 else 语句放在 if 块闭括号同一行的位置。
// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
- 如果一个 if 块总是执行一个 return 语句,那么接下来的 else 块就没有必要了。 如果一个包含 return 语句的 else if 块,在一个包含了 return 语句的 if 块之后,那么可以拆成多个 if 块。
// bad
function foo() {
if (x) {
return x;
} else {
return y;
}
}
// bad
function cats() {
if (x) {
return x;
} else if (y) {
return y;
}
}
// bad
function dogs() {
if (x) {
return x;
} else {
if (y) {
return y;
}
}
}
// good
function foo() {
if (x) {
return x;
}
return y;
}
// good
function cats() {
if (x) {
return x;
}
if (y) {
return y;
}
}
// good
function dogs(x) {
if (x) {
if (z) {
return y;
}
} else {
return z;
}
}
注释
- 使用 /** … */ 来进行多行注释。
- 使用 // 进行单行注释。 将单行注释放在需要注释的行的上方新行。 在注释之前放一个空行,除非它在块的第一行。
- 用一个空格开始所有的注释,使它更容易阅读。
- 使用 // FIXME: 注释一个问题。
- 使用 // TODO: 注释解决问题的方法。
空格
- 三元运算符’?:'前后
- 逗号后必须要有空格
- 代码块’{'前
- 下列关键字前:else, while, catch, finally
- 下列关键字后:if, else, for, while, do, switch, case, try,catch, finally, with, return, typeof
- 单行注释’//‘后(若单行注释和代码同行,则’//‘前也需要),多行注释’*'后
- 对象的属性值前
- for 循环,分号后留有一个空格,前置条件如果有多个,逗号后留一个空格
- 无论是函数声明还是函数表达式,’{'前一定要有空格
- 函数的参数之间
// not good
var a = {
b : 1
};
// good
var a = {
b: 1
};
// not good
++x;
y++;
z = x ? 1:2;
// good
++x;
y++;
z = x ? 1 : 2;
// not good
var a = [ 1, 2 ];
// good
var a = [1, 2];
// good
var doSomething = function(a, b, c) {
// do something
};
// good
doSomething(item);
// not good
for (let i = 0;i < 6;i++) {
x++;
}
// good
for (let i = 0; i < 6; i++) {
x++;
}
参考: