变量声明

使用const和let代替var

[强制]声明本地变量时,使用const和let,不要使用var,同时默认使用const,如果变量需要重新赋值,则使用let代替。

按需声明变量,声明之后尽快初始化

[建议]本地变量不要习惯性的在它们所包含代码块的起始处就进行声明,而应该在接近第一次使用之前进行声明,来减小他们的作用域。


数组

解构赋值

[强制]数组赋值时可以通过解构赋值从一个数组或迭代器中获取多个值,可以配合扩展运算符一起使用。对不需要关注的元素应该要省略。

示例:

  1. const [a, b, c, ...rest] = [1, 2, 3, 4, 5, 6];
  2. const [x, , y, , z] = [1, 2, 3, 4, 5, 6];

[建议]使用扩展操作符代替Array.prototype上的一些方法。

示例:

  1. // 数组拷贝
  2. const itemsCopy = [...items];
  3. // 数组合并,代替Array.prototype.concat
  4. const itemsConcat = [...arrayOne, ...arrayTwo];

[建议]使用Array.from方法来将类数组转换成真正的数组

示例:

  1. const foo = document.querySelectorAll('.foo');
  2. const nodes = Array.from(foo);

对象

方法和属性的简写

[强制]在定义对象时,可以使用方法和属性的简写形式。

示例:

  1. // 非简写
  2. const atom = {
  3. addValue: function (value) {
  4. return atom.value + value;
  5. },
  6. };
  7. const obj = {
  8. lukeSkywalker: lukeSkywalker,
  9. };
  10. // 简写
  11. const atom = {
  12. addValue(value) {
  13. return atom.value + value;
  14. },
  15. };
  16. const obj = {
  17. lukeSkywalker,
  18. };

这里需要注意,如果使用函数的简写形式或原function的形式,其中this是指所处的对象本身,但如果是使用箭头函数,那this是指向该对象外的作用域

对象的解构赋值

[建议]对象解构赋值与数组的解构赋值类似,不同点在于它是根据key来进行赋值的,与位置没关系。

示例:

  1. const obj = {
  2. first: 'hello',
  3. last: 'world',
  4. };
  5. const {
  6. first: f,
  7. last: l
  8. } = obj;
  9. // 此时f的值为'hello',l的值为'world'

对象的解构赋值也可用于函数的参数,但尽量使用简单的(只是有一个层级),不要使用有复杂的几层嵌套的属性。此外,关于默认值也与数组的解构赋值类似,形式如下:

  1. function destructured(ordinary, { num = 1, str = 'some default' } = {}) {
  2. // ...
  3. }

字符串

使用字符串模板

[强制]当需要动态拼接字符串时,比如字符串中包括一个变量,可以使用字符串模板。

示例:

  1. function sayHi(name) {
  2. return `How are you, ${name}?`;
  3. }

函数

使用剩余参数来代替arguments

[建议]剩余参数在语义和可读性上更好,而且它本身就是一个数组,不像arguments是一个类数组。

使用默认参数

[建议]使用参数的默认值语法代替在函数体内对参数的操作来进行默认值的处理。

  1. // bad
  2. function handleThings(opts) {
  3. opts = opts || {};
  4. // ...
  5. }
  6. // good
  7. function handleThings(opts = {}) {
  8. // ...
  9. }

默认值参数要放到函数参数列表的末尾

[强制]函数的参数列表中,要将默认值参数放在列表的最后部分。

  1. // bad
  2. function handleThings(opts = {}, name) {
  3. // ...
  4. }
  5. // good
  6. function handleThings(name, opts = {}) {
  7. // ...
  8. }

箭头函数

[建议]推荐使用箭头函数来代替function声明式的函数,特别是作为一个嵌套函数时。

  1. // bad
  2. [1, 2, 3].map(function (x) {
  3. const y = x + 1;
  4. return x * y;
  5. });
  6. // good
  7. [1, 2, 3].map(x => {
  8. const y = x + 1;
  9. return x * y;
  10. });

[强制]如果函数的参数只有一个,参数可以省略括号,也可以保留,但代码风格必须保持统一。

[建议]如果函数体只是单语句表达式,可以省略包裹函数体的大括号并使用隐式的return。

  1. // bad
  2. [1, 2, 3].map(number => {
  3. const nextNumber = number + 1;
  4. `A string containing the ${nextNumber}.`;
  5. });
  6. // good,单句表达式,省略大括号并使用隐式return
  7. [1, 2, 3].map(number => `A string containing the ${number}.`);
  8. // good
  9. [1, 2, 3].map((number) => {
  10. const nextNumber = number + 1;
  11. return `A string containing the ${nextNumber}.`;
  12. });
  13. // 当返回的是一个对象字面量时,要用括号括起来
  14. [1, 2, 3].map((number, index) => ({
  15. [index]: number,
  16. }));

不要直接修改函数的入参

[强制]不要直接修改函数的入参,这可能会造成意料之外的副作用,而且可读性不好,可以使用返回值来代替。


生成器函数

[强制]在原生环境不支持的情况下(浏览器端),不要使用生成器函数,即使你使用了babel之类的工具进行转换。


模块

模块导入

[建议]不要使用通配符的方式进行模块导入,这可以有效的保证你在导出模块时,会有一个默认导出(export default)。

  1. // bad
  2. import * as request from './request';
  3. // good
  4. import request from './request';

[强制]从同一个模块引入的内容使用一条import语句。

  1. // bad
  2. import foo from 'foo';
  3. // … some other imports … //
  4. import { named1, named2 } from 'foo';
  5. // good
  6. import foo, { named1, named2 } from 'foo';

不要导出可变绑定

[强制]除特殊场景,导出的内容都要求是一个常量引用。

  1. // bad
  2. let foo = 3;
  3. export { foo };
  4. // good
  5. const foo = 3;
  6. export { foo };

优先使用默认导出

[建议]如果一个模块中只一处导出,则使用默认导出代替具名导出,这样可以代码的可读性和可维护。

import语句放在文件的开头

[强制]import语句存在声明提升,所以应将模块引入语句集成中在文件的起始部分。