# JavaScript 编码规范
# 1 前言
本文档的目标是使 JavaScript 代码风格保持一致,容易被理解和被维护,主要用在浏览器端。
本文档参考了一些外部团队开源的代码规范,实现之处如有不便还请联系作者进行改善。
# 2 规范说明
目前 JS 开发中大部分使用 ECMAScript5 的语法,而 ES6 也颁布许久并且目前已经得到广泛浏览器的支持。ES6 在语法特性上更为简洁标准,并且修复了一些由于语言特性容易引起的 bug(比如箭头函数自带this),因此建议在开发时统一使用 ES6 标准。推荐阅读阮一峰的 ES6 教程基础部分。
本节内容的大多要求可以由编辑器指定如Prettier,Eslint等代码格式化工具自动处理。一部分需要在编辑器中进行设定。
# 1. 引用
1.1 【必须】 使用
const定义你的所有引用;避免使用var。 eslint:prefer-const,no-const-assign原因? 这样能够确保你不能重新赋值你的引用,否则可能导致错误或者产生难以理解的代码。
// bad var a = 1; var b = 2; // good const a = 1; const b = 2;1
2
3
4
5
6
71.2 【必须】 如果你必须重新赋值你的引用, 使用
let代替var。 eslint:no-var原因?
let是块级作用域,而不像var是函数作用域。// bad var count = 1; if (true) { count += 1; } // good, use the let. let count = 1; if (true) { count += 1; }1
2
3
4
5
6
7
8
9
10
11
# 2. 对象
2.1 【必须】 使用字面量语法创建对象。 eslint:
no-new-object// bad const item = new Object(); // good const item = {};1
2
3
4
52.2 【必须】 只使用引号标注无效标识符的属性。 eslint:
quote-props原因? 一般来说,我们认为这样更容易阅读。 它能更好地适配语法高亮显示功能,并且更容易通过许多 JS 引擎进行优化。
// bad const bad = { 'foo': 3, 'bar': 4, 'data-blah': 5, }; // good const good = { foo: 3, bar: 4, 'data-blah': 5, };1
2
3
4
5
6
7
8
9
10
11
12
13
# 3. 数组
3.1 【必须】 使用字面量语法创建数组。 eslint:
no-array-constructor// bad const items = new Array(); // good const items = [];1
2
3
4
53.2 【必须】 使用 Array#push 代替直接赋值来给数组添加项。
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');1
2
3
4
5
6
73.3 【必须】 使用数组展开符
...来拷贝数组。// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i += 1) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];1
2
3
4
5
6
7
8
9
10
113.4 【必须】 使用 Array.from 将一个类数组(array-like)对象转换成一个数组。
const arrLike = { 0: 'foo', 1: 'bar', 2: 'baz', length: 3 }; // bad const arr = Array.prototype.slice.call(arrLike); // good const arr = Array.from(arrLike);1
2
3
4
5
6
73.5 【必须】 使用 Array.from 代替展开符
...映射迭代器,因为它避免了创建一个中间数组。// bad const baz = [...foo].map(bar); // good const baz = Array.from(foo, bar);1
2
3
4
5
# 4. 解构
4.1 【必须】 在有多个返回值时, 使用对象解构,而不是数组解构。
原因? 你可以随时添加新的属性或者改变属性的顺序,而不用修改调用方。
// bad function processInput(input) { // 处理代码... return [left, right, top, bottom]; } // 调用者需要考虑返回数据的顺序。 const [left, __, top] = processInput(input); // good function processInput(input) { // 处理代码... return { left, right, top, bottom }; } // 调用者只选择他们需要的数据。 const { left, top } = processInput(input);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 5. 字符
5.1 【必须】 不应该用字符串跨行连接符的格式来跨行编写,这样会使当前行长度超过100个字符。
原因? 断开的字符串维护起来很痛苦,并且会提高索引难度。
// bad const errorMessage = 'This is a super long error that was thrown because \ of Batman. When you stop to think about how Batman had anything to do \ with this, you would get nowhere \ fast.'; // bad const errorMessage = 'This is a super long error that was thrown because ' + 'of Batman. When you stop to think about how Batman had anything to do ' + 'with this, you would get nowhere fast.'; // good const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';1
2
3
4
5
6
7
8
9
10
11
12
135.2 【必须】 构建字符串时,使用字符串模板代替字符串拼接。 eslint:
prefer-templatetemplate-curly-spacing原因? 字符串模板为您提供了一种可读的、简洁的语法,具有正确的换行和字符串插值特性。
// bad function sayHi(name) { return 'How are you, ' + name + '?'; } // bad function sayHi(name) { return ['How are you, ', name, '?'].join(); } // bad function sayHi(name) { return `How are you, ${ name }?`; } // good function sayHi(name) { return `How are you, ${name}?`; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
195.3 【必须】 永远不要使用
eval()执行放在字符串中的代码,它导致了太多的漏洞。 eslint:no-eval5.4 【必须】 不要在字符串中转义不必要的字符。 eslint:
no-useless-escape原因? 反斜杠损害了可读性,因此只有在必要的时候才可以出现。
// bad const foo = '\'this\' \i\s \"quoted\"'; // good const foo = '\'this\' is "quoted"'; const foo = `my name is '${name}'`;1
2
3
4
5
6
# 6. 函数
6.1 【必须】 把立即执行函数包裹在圆括号里。 eslint:
wrap-iife原因? 立即调用的函数表达式是个独立的单元 - 将它和它的调用括号还有入参包装在一起可以非常清晰的表明这一点。请注意,在一个到处都是模块的世界中,您几乎用不到 IIFE。
// immediately-invoked function expression (IIFE) 立即调用的函数表达式 (function () { console.log('Welcome to the Internet. Please follow me.'); }());1
2
3
46.2 【必须】 切记不要在非功能块中声明函数 (
if,while, 等)。 请将函数赋值给变量。 浏览器允许你这样做, 但是不同浏览器会有不同的行为, 这并不是什么好事。 eslint:no-loop-func6.3 【必须】 ECMA-262 将
block定义为语句列表。 而函数声明并不是语句。// bad if (currentUser) { function test() { console.log('Nope.'); } } // good let test; if (currentUser) { test = () => { console.log('Yup.'); }; }1
2
3
4
5
6
7
8
9
10
11
12
13
146.4 【必须】 永远不要给一个参数命名为
arguments。 这将会覆盖函数默认的arguments对象。// bad function foo(name, options, arguments) { // ... } // good function foo(name, options, args) { // ... }1
2
3
4
5
6
7
8
96.5 【必须】 使用默认参数时避免副作用。
原因? 他们很容易混淆。
var b = 1; // bad function count(a = b++) { console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 31
2
3
4
5
6
7
8
96.6 【必须】 函数声明语句中需要空格。 eslint:
space-before-function-parenspace-before-blocks原因? 一致性很好,在删除或添加名称时不需要添加或删除空格。
// bad const f = function(){}; const g = function (){}; const h = function() {}; // good const x = function () {}; const y = function a() {};1
2
3
4
5
6
7
8
# 7. 类和构造器
7.1 【必须】 避免定义重复的类成员。 eslint:
no-dupe-class-members原因? 重复的类成员声明将会默认使用最后一个 - 具有重复的类成员可以说是一个bug。
// bad class Foo { bar() { return 1; } bar() { return 2; } } // good class Foo { bar() { return 1; } }1
2
3
4
5
6
7
8
9
10
11
# 8. 模块
8.1 【必须】 对于同一个路径,只在一个地方引入所有需要的东西。 eslint:
no-duplicates原因? 对于同一个路径,如果存在多行引入,会使代码更难以维护。
// bad import foo from 'foo'; // … 其他导入 … // import { named1, named2 } from 'foo'; // good import foo, { named1, named2 } from 'foo'; // good import foo, { named1, named2, } from 'foo';1
2
3
4
5
6
7
8
9
10
11
12
138.2 【必须】 将所有的
imports 语句放在其他语句之前。 eslint:import/first原因? 将所有的
imports 提到顶部,可以防止某些诡异行为的发生。// bad import foo from 'foo'; foo.init(); import bar from 'bar'; // good import foo from 'foo'; import bar from 'bar'; foo.init();1
2
3
4
5
6
7
8
9
10
11
# 9. 变量
9.1 【必须】 变量应先声明再使用,禁止引用任何未声明的变量,除非你明确知道引用的变量存在于当前作用域链上。禁止不带任何关键词定义变量,这样做将会创建一个全局变量,污染全局命名空间,造成程序意料之外的错误。 eslint:
no-undefprefer-const// bad, 这会创建一个全局变量 superPower = new SuperPower(); // good const superPower = new SuperPower(); // bad, 容易污染外部变量 let superPower = 'a'; (function() { superPower = 'b'; })(); console.log(superPower); // good let superPower = 'a'; (function() { let superPower = 'b'; })(); console.log(superPower); // bad, 更常见的情况是这样的,在 for 循环里的 i 将会污染外部的变量 i let i = 1; (function() { for (i = 0; i < 10; i++) { console.log('inside', i); } console.log('outside', i) })(); console.log('global', i); // good let i = 1; (function() { // i 的作用域在 for 循环内 for (let i = 0; i < 10; i++) { console.log('inside i', i); } // 如果真的需要在 for 循环外使用循环变量,应该先定义在外部 let j; for (j = 0; j < 10; j++) { console.log('inside j:', j); } console.log('outside j', j); })(); console.log('global', i);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
499.2 【必须】 不要链式变量赋值。 eslint:
no-multi-assign原因? 链式变量赋值会创建隐式全局变量。
// bad (function example() { /** * JavaScript 把它解释为 * let a = ( b = ( c = 1 ) ); * let 关键词只适用于变量 a,变量 b 和变量 c 则变成了全局变量。 */ let a = b = c = 1; }()); // throws ReferenceError console.log(a); // 1 console.log(b); // 1 console.log(c); // good (function example() { let a = 1; let b = a; let c = a; }()); // throws ReferenceError console.log(a); // throws ReferenceError console.log(b); // throws ReferenceError console.log(c); // 对于 `const` 也一样1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
329.3 【必须】 避免使用不必要的递增和递减操作符 (
++,--)。 eslintno-plusplus原因? 在eslint文档中,一元操作符
++和--会自动添加分号,不同的空白可能会改变源代码的语义。建议使用num += 1这样的语句来做递增和递减,而不是使用num++或num ++。同时++num和num++的差异也使代码的可读性变差。不必要的增量和减量语句会导致无法预先明确递增/预递减值,这可能会导致程序中的意外行为。但目前依然允许在 for loop 中使用
++、--的语法,但依然建议尽快迁移到+= 1、-= 1的语法。 #22// bad, i = 11, j = 20 let i = 10; let j = 20; i ++ j // bad, i = 10, j = 21 let i = 10; let j = 20; i ++ j // bad const array = [1, 2, 3]; let num = 1; num++; --num; // not good, just acceptable for upforward compatible. let sum = 0; let truthyCount = 0; for (let i = 0; i < array.length; i++) { let value = array[i]; sum += value; if (value) { truthyCount++; } } // good const array = [1, 2, 3]; let num = 1; num += 1; num -= 1; // good const sum = array.reduce((a, b) => a + b, 0); const truthyCount = array.filter(Boolean).length;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
399.4 【必须】 避免在赋值语句
=前后换行。如果你的代码单行长度超过了max-len定义的长度而不得不换行,那么使用括号包裹。 eslintoperator-linebreak.原因? 在
=前后换行,可能混淆赋的值。// bad const foo = 'superLongLongLongLongLongLongLongLongString'; // bad const bar = superLongLongLongLongLongLongLongLongFunctionName(); // bad const fullHeight = borderTop + innerHeight + borderBottom; // bad const anotherHeight = borderTop + innerHeight + borderBottom; // bad const thirdHeight = ( borderTop + innerHeight + borderBottom ); // good - max-len 会忽略字符串,直接写后面即可。 const foo = 'superLongLongLongLongLongLongLongLongString'; // good const bar = ( superLongLongLongLongLongLongLongLongFunctionName() ); // good const fullHeight = borderTop + innerHeight + borderBottom; // good const anotherHeight = borderTop + innerHeight + borderBottom; // good const thirdHeight = ( borderTop + innerHeight + borderBottom );1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
509.5 【必须】 禁止定义了变量却不使用它。 eslint:
no-unused-vars原因? 在代码里到处定义变量却没有使用它,不完整的代码结构看起来像是个代码错误。即使没有使用,但是定义变量仍然需要消耗资源,并且对阅读代码的人也会造成困惑,不知道这些变量是要做什么的。
// bad let some_unused_var = 42; // bad,定义了变量不意味着就是使用了 let y = 10; y = 5; // bad,对自身的操作并不意味着使用了 let z = 0; z = z + 1; // bad, 未使用的函数参数 function getX(x, y) { return x; } // good function getXPlusY(x, y) { return x + y; } let x = 1; let y = a + 2; alert(getXPlusY(x, y)); /** * 有时候我们想要提取某个对象排除了某个属性外的其他属性,会用 rest 参数解构对象 * 这时候 type 虽然未使用,但是仍然被定义和赋值,这也是一种空间的浪费 * type 的值是 'a' * coords 的值是 data 对象,但是没有 type 属性 { example1: 'b', example2: 'c' } */ let data = { type: 'a', example1: 'b', example2: 'c' } let { type, ...coords } = data;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 10. 比较运算符和等号
10.1 【必须】 在
case和default的子句中,如果存在声明 (例如.let,const,function, 和class),使用大括号来创建块级作用域。 eslint:no-case-declarations原因? 变量声明的作用域在整个 switch 语句内,但是只有在 case 条件为真时变量才会被初始化。 当多个
case语句定义相同的变量时,就会导致变量覆盖的问题。// bad switch (foo) { case 1: let x = 1; break; case 2: const y = 2; break; case 3: function f() { // ... } break; default: class C {} } // good switch (foo) { case 1: { let x = 1; break; } case 2: { const y = 2; break; } case 3: { function f() { // ... } break; } case 4: bar(); break; default: { class C {} } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
4010.2 【必须】 使用混合运算符时,使用小括号括起来需要一起计算的部分,只要觉得有必要,那么尽可能地用括号让代码的优先级更明显。 eslint:
no-mixed-operators原因? 这能提高可读性并且表明开发人员的意图。
// bad const foo = a && b < 0 || c > 0 || d + 1 === 0; // bad const bar = a ** b - 5 % d; // bad, 可能陷入一种 (a || b) && c 的思考 if (a || b && c) { return d; } // good const foo = (a && b < 0) || (c > 0) || (d + 1 === 0); // good const bar = (a ** b) - (5 % d); // good if (a || (b && c)) { return d; } // good const bar = a + (b / c * d);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 11. 代码块
11.1 【必须】 当有多行代码块的时候,应使用大括号包裹。 eslint:
nonblock-statement-body-position// bad if (test) return false; // bad let condition = true; let test = 1; // 在缩进不规范的时候,容易造成误解 if (condition) condition = false; test = 2; // good if (test) return false; // good if (test) { return false; } // bad function foo() { return false; } // good function bar() { return false; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2711.2 【必须】 如果你使用的是
if和else的多行代码块,则将else语句放在if块闭括号同一行的位置。 eslint:brace-style// bad if (test) { thing1(); thing2(); } else { thing3(); } // good if (test) { thing1(); thing2(); } else { thing3(); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 12. 控制语句
12.1 【必须】 不要使用选择操作符代替控制语句。
// bad !isRunning && startRunning(); // good if (!isRunning) { startRunning(); }1
2
3
4
5
6
7
# 13. 注释
13.1 【必须】 使用
/** ... */来进行多行注释。// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2413.2 【必须】 用一个空格开始所有的注释,使它更容易阅读。 eslint:
spaced-comment// bad //is current tab const active = true; // good // is current tab const active = true; // bad /** *make() returns a new element *based on the passed-in tag name */ function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 14. 空白
14.1 【必须】 在控制语句中的左括号前放置1个空格(if,while等)。在函数调用和声明中,参数列表和函数名之间不能留空格。
keyword-spacing// bad if(isJedi) { fight (); } // good if (isJedi) { fight(); } // bad function fight () { console.log ('Swooosh!'); } // good function fight() { console.log('Swooosh!'); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1914.2 【必须】 运算符左右设置各设置一个空格 eslint:
space-infix-ops// bad const x=y+5; // good const x = y + 5;1
2
3
4
514.3 【必须】 在文件的结尾需要保留一个空行 eslint:
eol-last// bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6;1
2
3
4// bad import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵ ↵1
2
3
4
5// good import { es6 } from './AirbnbStyleGuide'; // ... export default es6;↵1
2
3
414.4 【必须】 不要在块的开头使用空白行。 eslint:
padded-blocks// bad function bar() { console.log(foo); } // bad if (baz) { console.log(qux); } else { console.log(foo); } // bad class Foo { constructor(bar) { this.bar = bar; } } // good function bar() { console.log(foo); } // good if (baz) { console.log(qux); } else { console.log(foo); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
3514.5 【必须】 不要使用多个空行填充代码。 eslint:
no-multiple-empty-lines// bad class Person { constructor(fullName, email, birthday) { this.fullName = fullName; this.email = email; this.setAge(birthday); } setAge(birthday) { const today = new Date(); const age = this.getAge(today, birthday); this.age = age; } getAge(today, birthday) { // .. } } // good class Person { constructor(fullName, email, birthday) { this.fullName = fullName; this.email = email; this.setAge(birthday); } setAge(birthday) { const today = new Date(); const age = getAge(today, birthday); this.age = age; } getAge(today, birthday) { // .. } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
4714.6 【必须】 不要在括号内添加空格。 eslint:
space-in-parens// bad function bar( foo ) { return foo; } // good function bar(foo) { return foo; } // bad if ( foo ) { console.log(foo); } // good if (foo) { console.log(foo); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1914.7 【必须】 不要在中括号中添加空格。 eslint:
array-bracket-spacing// bad const foo = [ 1, 2, 3 ]; console.log(foo[ 0 ]); // good const foo = [1, 2, 3]; console.log(foo[0]);1
2
3
4
5
6
714.8 【必须】 避免让你的代码行超过120个字符(包括空格)。 注意:根据上边的规则,长字符串编写可不受该规则约束,不应该被分解。 eslint:
max-len原因? 这样能够提升代码可读性和可维护性。
// bad const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // bad $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' } }).done(() => console.log('Congratulations!')).fail(() => console.log('You have failed this city.')); // good const foo = jsonData && jsonData.foo && jsonData.foo.bar && jsonData.foo.bar.baz && jsonData.foo.bar.baz.quux && jsonData.foo.bar.baz.quux.xyzzy; // good $.ajax({ method: 'POST', url: 'https://airbnb.com/', data: { name: 'John' }, }) .done(() => console.log('Congratulations!')) .fail(() => console.log('You have failed this city.'));1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2214.9 【必须】 要求打开的块标志和同一行上的标志拥有一致的间距。此规则还会在同一行关闭的块标记和前边的标记强制实施一致的间距。 eslint:
block-spacing// bad function foo() {return true;} if (foo) { bar = 0;} // good function foo() { return true; } if (foo) { bar = 0; }1
2
3
4
5
6
714.10 【必须】 逗号之前避免使用空格,逗号之后需要使用空格。eslint:
comma-spacing// bad const arr = [1 , 2]; // good const arr = [1, 2];1
2
3
4
514.11 【必须】 避免在函数名及其入参括号之间插入空格。 eslint:
func-call-spacing// bad func (); func (); // good func();1
2
3
4
5
6
7
814.12 【必须】 在对象的属性和值之间的冒号前不加空格,冒号后加空格。 eslint:
key-spacing// bad var obj = { foo : 42 }; var obj2 = { foo:42 }; // good var obj = { foo: 42 };1
2
3
4
5
614.13 【必须】 避免在行尾添加空格。 eslint:
no-trailing-spaces14.14 【必须】 在代码开始处不允许存在空行,行间避免出现多个空行,而结尾处必须保留一个空行。 eslint:
no-multiple-empty-lines// bad const x = 1; const y = 2; // good const x = 1; const y = 2;1
2
3
4
5
6
7
8
9
10
11
# 15. 逗号
15.1 【必须】 逗号不能前置 eslint:
comma-style// bad const story = [ once , upon , aTime ]; // good const story = [ once, upon, aTime, ]; // bad const hero = { firstName: 'Ada' , lastName: 'Lovelace' , birthYear: 1815 , superPower: 'computers' }; // good const hero = { firstName: 'Ada', lastName: 'Lovelace', birthYear: 1815, superPower: 'computers', };1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 16. jQuery
16.1 【推荐】 对于 jQuery 对象一律使用
$符作为前缀。// bad const sidebar = $('.sidebar'); // good const $sidebar = $('.sidebar'); // good const $sidebarBtn = $('.sidebar-btn');1
2
3
4
5
6
7
816.2 【推荐】 缓存 jQuery 查询,节省 DOM 查询开销。
// bad function setSidebar() { $('.sidebar').hide(); // ... $('.sidebar').css({ 'background-color': 'pink', }); } // good function setSidebar() { const $sidebar = $('.sidebar'); $sidebar.hide(); // ... $sidebar.css({ 'background-color': 'pink', }); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2216.3 【推荐】 能通过一次调用查找到的,不要分多次;在已有对象内查询,使用
find函数,减少重复查询。// bad $('ul', '.sidebar').hide(); // bad $('.sidebar').find('ul').hide(); // good $('.sidebar ul').hide(); // good $('.sidebar > ul').hide(); // good $sidebar.find('ul').hide();1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 17. 命名规范
17.1 【必须】 使用驼峰命名法(camelCase)命名对象、函数和实例。 eslint:
camelcase// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}1
2
3
4
5
6
7
817.2 【必须】 只有在命名构造器或者类的时候,才用帕斯卡拼命名法(PascalCase),即首字母大写。 eslint:
new-cap// bad function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // good class User { constructor(options) { this.name = options.name; } } const good = new User({ name: 'yup', });1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1917.3 【必须】 导出默认函数时使用驼峰命名法,并且文件名应该和方法名相同。文件名建议使用 kebab-case,后缀为小写。
function makeStyleGuide() { // ... } export default makeStyleGuide;1
2
3
4
517.4 【必须】 当导出构造器 / 类 / 单例 / 函数库 / 对象时应该使用帕斯卡命名法(首字母大写)。
const TencentStyleGuide = { es6: { }, }; export default TencentStyleGuide;1
2
3
4
5
6
# 18. 分号
-
原因? 当 JavaScript 解析器解析到没有分号的单行代码时,它会使用一个叫做 自动分号插入算法(Automatic Semicolon Insertion) 来确定是否应该以换行符视为语句的结束,如果判断为语句结束,会在代码中断前插入一个分号到代码中。 但是,ASI 包含了一些奇怪的行为,如果 JavaScript 错误的解释了你的换行符,你的代码将会中断。 随着越来越多的新特性成为 JavaScript 的一部分,这些规则将变得更加复杂。明确地终止你的语句,并配置你的 linter 以捕获缺少分号的代码行,将有助于预防此类问题。
// bad - 可能异常 const jedis = {} ['luke', 'leia'].some((name) => { jedis[name] = true return true }) // bad - 可能异常 const reaction = "No! That's impossible!" (async function meanwhileOnTheFalcon() { // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` // ... }()) // bad - 返回 `undefined` 而不是下一行的值 - 当 `return` 单独一行的时候 ASI 总是会发生 function foo() { return 'search your feelings, you know it to be foo' } // good const jedis = {}; ['luke', 'leia'].some((name) => { jedis[name] = true; return true; }); // good const reaction = "No! That's impossible!"; (async function meanwhileOnTheFalcon() { // handle `leia`, `lando`, `chewie`, `r2`, `c3p0` // ... }()); // good function foo() { return 'search your feelings, you know it to be foo'; }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38