JavaScript 编程规范(二)

本文详细介绍ESLint代码规范,包括变量声明、控制语句、运算符使用、代码块、注释、空格、类型转换、命名规则等内容,旨在提升代码质量和可读性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 总是使用 const 或 let 来声明变量。 不这样做会导致产生全局变量。 我们希望避免污染全局命名空间。

eslint: no-undef prefer-const

 
  1. // bad

  2. superPower = new SuperPower();

  3. // good

  4. const superPower = new SuperPower();

2. 将所有的 const 和 let 分组 。

当你需要把已分配的变量分配给一个变量时非常有用

 
  1. // bad

  2. let i, len, dragonball,

  3. items = getItems(),

  4. goSportsTeam = true;

  5. // bad

  6. let i;

  7. const items = getItems();

  8. let dragonball;

  9. const goSportsTeam = true;

  10. let len;

  11. // good

  12. const goSportsTeam = true;

  13. const items = getItems();

  14. let dragonball;

  15. let i;

  16. let length;

3. 变量不要链式赋值。

eslint: no-multi-assign

eslint: no-multi-assign

 
  1. // bad

  2. (function example() {

  3. // JavaScript 将其解析为

  4. // let a = ( b = ( c = 1 ) );

  5. // let关键字只适用于变量a;

  6. // 变量b和c变成了全局变量。

  7. let a = b = c = 1;

  8. }());

  9. console.log(a); // 抛出 ReferenceError(引用错误)

  10. console.log(b); // 1

  11. console.log(c); // 1

  12. // good

  13. (function example() {

  14.     let a = 1;

  15.     let b = a;

  16.     let c = a;

  17. }());

  18. console.log(a); // 抛出 ReferenceError(引用错误)

  19. console.log(b); // 抛出 ReferenceError(引用错误)

  20. console.log(c); // 抛出 ReferenceError(引用错误)

  21. // 同样适用于 `const`

4. 避免使用一元递增和递减运算符(++, -–)。

根据 eslint 文档,一元递增和递减语句会受到自动插入分号的影响,并可能导致应用程序中的值递增或递减,从而导致无提示错误。使用像 num += 1 而不是 num++ 或 num ++ 这样的语句来改变你的值也更具有表现力。不允许一元递增和递减语句也会阻止您无意中预先递增/递减值,这也会导致程序中的意外行为。

 
  1. // bad

  2. const array = [1, 2, 3];

  3. let num = 1;

  4. num++;

  5. --num;

  6. let sum = 0;

  7. let truthyCount = 0;

  8. for (let i = 0; i < array.length; i++) { 

  9.   let value = array[i]; 

  10.   sum += value;

  11.    if (value) {

  12.       truthyCount++; 

  13.     } 

  14.  }

  15. // good 

  16. const array = [1, 2, 3]; 

  17. let num = 1; num += 1; num -= 1; 

  18. const sum = array.reduce((a, b) => a + b, 0);

  19. const truthyCount = array.filter(Boolean).length;

比较运算符 Comparison Operators 和 等号 Equality

1. 使用 === 和 !== 优先于 == 和 !=。

eslint: eqeqeq

2. 对于布尔值使用简写,但对于字符串和数字使用显式比较。

 
  1. // bad

  2. if (isValid === true) {

  3. // ...

  4. }

  5. // good

  6. if (isValid) {

  7. // ...

  8. }

  9. // bad

  10. if (name) {

  11. // ...

  12. }

  13. // good

  14. if (name !== '') {

  15. // ...

  16. }

  17. // bad

  18. if (collection.length) {

  19. // ...

  20. }

  21. // good

  22. if (collection.length > 0) {

  23. // ...

  24. }

3. 在 case 和 default 子句中,使用大括号来创建包含词法声明的语句块(例如 let, const, function, 和 class).

eslint: no-case-declarations

 
  1. // bad

  2. switch (foo) {

  3.   case 1:

  4.     let x = 1;

  5.   break;

  6.   case 2:

  7.     const y = 2;

  8.   break;

  9.   case 3:

  10.     function f() {

  11.       // ...

  12.     }

  13.   break;

  14. default:

  15.   class C {}

  16. }

  17. // good

  18. switch (foo) {

  19.   case 1: {

  20.     let x = 1;

  21.     break;

  22.   }

  23.   case 2: {

  24.     const y = 2;

  25.     break;

  26.   }

  27.   case 3: {

  28.     function f() {

  29.       // ...

  30.     }

  31.     break;

  32.   }

  33.   case 4:

  34.     bar();

  35.     break;

  36.   default: {

  37.     class C {}

  38.   }

  39. }

4. 三元表达式不应该嵌套,通常写成单行表达式。

eslint: no-nested-ternary

 
  1. // bad

  2. const foo = maybe1 > maybe2

  3. ? "bar"

  4. : value1 > value2 ? "baz" : null;

  5. // 拆分成2个分离的三元表达式

  6. const maybeNull = value1 > value2 ? 'baz' : null;

  7. // better

  8. const foo = maybe1 > maybe2

  9. ? 'bar'

  10. : maybeNull;

  11. // best

  12. const foo = maybe1 > maybe2 ? 'bar' : maybeNull;

5. 避免不必要的三元表达式语句。

eslint: no-unneeded-ternary

 
  1. / bad

  2. const foo = a ? a : b;

  3. const bar = c ? true : false;

  4. const baz = c ? false : true;

  5. // good

  6. const foo = a || b;

  7. const bar = !!c;

  8. const baz = !c;

6. 当运算符混合在一个语句中时,请将其放在括号内。混合算术运算符时,不要将 * 和 % 与 + , -,,/ 混合在一起。

eslint: no-mixed-operators

这可以提高可读性,并清晰展现开发者的意图。

 
  1. / bad

  2. const foo = a && b < 0 || c > 0 || d + 1 === 0;

  3. // bad

  4. const bar = a ** b - 5 % d;

  5. // bad

  6. if (a || b && c) {

  7. return d;

  8. }

  9. // good

  10. const foo = (a && b < 0) || c > 0 || (d + 1 === 0);

  11. // good

  12. const bar = (a ** b) - (5 % d);

  13. // good

  14. if ((a || b) && c) {

  15. return d;

  16. }

  17. // good

  18. const bar = a + b / c * d;

代码块 Blocks

1. 使用大括号包裹所有的多行代码块

eslint: nonblock-statement-body-position

 
  1. // bad

  2. if (test)

  3.   return false;

  4. // good

  5. if (test) return false;

  6. // good

  7. if (test) {

  8.   return false;

  9. }

  10. // bad

  11. function foo() { return false; }

  12. // good

  13. function bar() {

  14.   return false;

  15. }

2. 如果通过 if 和 else 使用多行代码块,把 else 放在 if 代码块闭合括号的同一行。

eslint: brace-style

 
  1. // bad

  2. if (test) {

  3.   thing1();

  4.   thing2();

  5. }

  6. else {

  7.   thing3();

  8. }

  9. // good

  10. if (test) {

  11.   thing1();

  12.   thing2();

  13. } else {

  14.   thing3();

  15. }

3. 如果一个 if 块总是执行一个 return 语句,后面的 else 块是不必要的。在 else if 块中的 return,可以分成多个 if 块来 return 。

eslint: no-else-return

 
  1. // bad

  2. function foo() {

  3.   if (x) {

  4.     return x;

  5.   } else {

  6.     return y;

  7.   }

  8. }

  9. // bad

  10. function cats() {

  11.   if (x) {

  12.     return x;

  13.   } else if (y) {

  14.     return y;

  15.   }

  16. }

  17. // bad

  18. function dogs() {

  19.   if (x) {

  20.     return x;

  21.   } else {

  22.   if (y) {

  23.     return y;

  24.   }

  25. }

  26. }

  27. // good

  28. function foo() {

  29.   if (x) {

  30.     return x;

  31.   }

  32. return y;

  33. }

  34. // good

  35. function cats() {

  36.   if (x) {

  37.     return x;

  38.   }

  39.   if (y) {

  40.     return y;

  41.   }

  42. }

  43. //good

  44. function dogs(x) {

  45.   if (x) {

  46.     if (z) {

  47.       return y;

  48.   }

  49. } else {

  50.   return z;

  51.   }

  52. }

控制语句 Control Statements

1. 如果您的控制语句(if, while 的)太长或超过最大行长度,那么每个(分组)条件可以放单独一行。逻辑运算符应该放在每行起始处。

 
  1. // bad

  2. if ((foo === 123 || bar === 'abc') && doesItLookGoodWhenItBecomesThatLong() && isThisReallyHappening()) {

  3.  thing1();

  4. }

  5. // bad

  6. if (foo === 123 &&

  7.   bar === 'abc') {

  8.   thing1();

  9. }

  10. // bad

  11. if (foo === 123

  12.   && bar === 'abc') {

  13.   thing1();

  14. }

  15. // bad

  16. if (

  17.   foo === 123 &&

  18.   bar === 'abc'

  19. ) {

  20.   thing1();

  21. }

  22. // good

  23. if (

  24.   foo === 123

  25.   && bar === 'abc'

  26. ) {

  27.   thing1();

  28. }

  29. // good

  30. if (

  31.   (foo === 123 || bar === "abc")

  32.   && doesItLookGoodWhenItBecomesThatLong()

  33.   && isThisReallyHappening()

  34. ) {

  35.   thing1();

  36. }

  37. // good

  38. if (foo === 123 && bar === 'abc') {

  39.   thing1();

  40. }

注释 Comments

1. 多行注释使用 / … /。

 
  1. /**

  2. * @param {Grid} grid 需要合并的Grid

  3. * @param {Array} cols 需要合并列的Index(序号)数组;从0开始计数,序号也包含。

  4. * @param {Boolean} isAllSome 是否2个tr的cols必须完成一样才能进行合并。true:完成一样;false(默认):不完全一样

  5. * @return void

  6. * @author 单志永 2018/11/8

  7. */

  8. function mergeCells(grid, cols, isAllSome) {

  9.     // Do Something

  10. }

2. 单行注释使用 // 。将单行注释放在需注释的语句上方。在注释之前放置一个空行,除非它位于代码块的第一行。

 
  1. // bad

  2. const active = true;  // is current tab

  3. // good

  4. // is current tab

  5. const active = true;

  6. // bad

  7. function getType() {

  8.   console.log('fetching type...');

  9.   // set the default type to 'no type'

  10.   const type = this.type || 'no type';

  11.   return type;

  12. }

  13. // good

  14. function getType() {

  15.   console.log('fetching type...');

  16.   // set the default type to 'no type'

  17.   const type = this.type || 'no type';

  18.   return type;

  19. }

  20. // also good

  21. function getType() {

  22.   // set the default type to 'no type'

  23.   const type = this.type || 'no type';

  24.   return type;

  25. }

3. 所有注释符和注释内容用一个空格隔开,让它更容易阅读。

eslint: spaced-comment

 
  1. // bad

  2. //is current tab

  3. const active = true;

  4. // good

  5. // is current tab

  6. const active = true;

  7. // bad

  8. /**

  9. *make() returns a new element

  10. *based on the passed-in tag name

  11. */

  12. function make(tag) {

  13. // ...

  14. return element;

  15. }

  16. // good

  17. /**

  18. * make() returns a new element

  19. * based on the passed-in tag name

  20. */

  21. function make(tag) {

  22. // ...

  23. return element;

  24. }

4. 给注释增加 FIXME 或 TODO 的前缀,可以帮助其他开发者快速了解这个是否是一个需要重新复查的问题,或是你正在为需要解决的问题提出解决方案。这将有别于常规注释,因为它们是可操作的。使用 FIXME – need to figure this out 或者 TODO – need to implement。

使用 // FIXME: 来标识需要修正的问题。注:如果代码中有该标识,说明标识处代码需要修正,甚至代码是错误的,不能工作,需要修复,如何修正会在说明中简略说明。

 
  1. lass Calculator extends Abacus {

  2.   constructor() {

  3.     super();

  4.     // FIXME: shouldn’t use a global here

  5.     total = 0;

  6.   }

  7. }

使用 // TODO: 来标识需要实现的问题。注:如果代码中有该标识,说明在标识处有功能代码待编写,待实现的功能在说明中会简略说明。

 
  1. class Calculator extends Abacus {

  2.   constructor() {

  3.     super();

  4.     // TODO: total should be configurable by an options param

  5.     this.total = 0;

  6.   }

  7. }

空格 Whitespace

1. 使用 2 个空格作为缩进

 
  1. // bad

  2. function foo() {

  3. ∙∙∙∙let name;

  4. }

  5. // bad

  6. function bar() {

  7. ∙let name;

  8. }

  9. // good

  10. function baz() {

  11. ∙∙let name;

  12. }

2. 在大括号前放置 1 个空格。

eslint: space-before-blocks jscs: requireSpaceBeforeBlockStatements

 
  1. // bad

  2. function test(){

  3.   console.log('test');

  4. }

  5. // good

  6. function test() {

  7.   console.log('test');

  8. }

  9. // bad

  10. dog.set('attr',{

  11.   age: '1 year',

  12.   breed: 'Bernese Mountain Dog',

  13. });

  14. // good

  15. dog.set('attr', {

  16.   age: '1 year',

  17.   breed: 'Bernese Mountain Dog',

  18. });

3. 在控制语句(if、while 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。

eslint: keyword-spacing jscs: requireSpaceAfterKeywords

 
  1. // bad

  2. if(isJedi) {

  3.   fight ();

  4. }

  5. // good

  6. if (isJedi) {

  7.   fight();

  8. }

  9. // bad

  10. function fight () {

  11.   console.log ('Swooosh!');

  12. }

  13. // good

  14. function fight() {

  15.   console.log('Swooosh!');

  16. }

4. 使用空格把运算符隔开。

eslint: space-infix-ops jscs: requireSpaceBeforeBinaryOperators, requireSpaceAfterBinaryOperators

 
  1. // bad

  2. const x=y+5;

  3. // good

  4. const x = y + 5;

5. 在文件末尾插入一个空行。

eslint: eol-last

 
  1. // bad

  2. import { es6 } from './AirbnbStyleGuide';

  3. // ...

  4. export default es6;

  5.  
  6. // bad

  7. import { es6 } from './AirbnbStyleGuide';

  8. // ...

  9. export default es6;

  10.  
  11. // good

  12. import { es6 } from './AirbnbStyleGuide';

  13. // ...

  14. export default es6;

6. 长方法链式调用时使用缩进(2个以上的方法链式调用)。使用一个点 . 开头,强调该行是一个方法调用,不是一个新的声明。

eslint: newline-per-chained-call no-whitespace-before-property

 
  1. // bad

  2. $('#items').find('.selected').highlight().end().find('.open').updateCount();

  3.  
  4. // bad

  5. $('#items').

  6. find('.selected').

  7. highlight().

  8. end().

  9. find('.open').

  10. updateCount();

  11.  
  12. // good

  13. $('#items')

  14. .find('.selected')

  15. .highlight()

  16. .end()

  17. .find('.open')

  18. .updateCount();

  19.  
  20. // bad

  21. const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)

  22. .attr('width', (radius + margin) * 2).append('svg:g')

  23. .attr('transform', `translate(${radius + margin},${radius + margin})`)

  24. .call(tron.led);

  25. // good

  26. const leds = stage.selectAll('.led')

  27. .data(data)

  28. .enter().append('svg:svg')

  29. .classed('led', true)

  30. .attr('width', (radius + margin) * 2)

  31. .append('svg:g')

  32. .attr('transform', `translate(${radius + margin},${radius + margin})`)

  33. .call(tron.led);

  34.  
  35. // good

  36. const leds = stage.selectAll('.led').data(data);

7. 不要在圆括号内加空格。

 
  1. // bad

  2. function bar( foo ) {

  3.   return foo;

  4. }

  5. // good

  6. function bar(foo) {

  7.   return foo;

  8. }

  9. // bad

  10. if ( foo ) {

  11.   console.log(foo);

  12. }

  13. // good

  14. if (foo) {

  15.   console.log(foo);

  16. }

8. 不要在中括号内添加空格。

eslint: array-bracket-spacing jscs: disallowSpacesInsideArrayBrackets

 
  1. // bad

  2. const foo = [ 1, 2, 3 ];

  3. console.log(foo[ 0 ]);

  4. // good

  5. const foo = [1, 2, 3];

  6. console.log(foo[0]);

*9. 在大括号内添加空格

 
  1. // bad

  2. const foo = {clark: 'kent'};

  3. // good

  4. const foo = { clark: 'kent' };

类型转换 Type Casting & Coercion

1. 在声明语句的开始处就执行强制类型转换.

字符串:

eslint: no-new-wrappers

 
  1. // => this.reviewScore = 9;

  2. // bad

  3. const totalScore = new String(this.reviewScore); // typeof totalScore 是 "object" 而不是 "string"

  4. // bad

  5. const totalScore = this.reviewScore + ''; // 调用 this.reviewScore.valueOf()

  6. // bad

  7. const totalScore = this.reviewScore.toString(); // 不能保证返回一个字符串

  8. // good

  9. const totalScore = String(this.reviewScore);

数字:使用 Number 进行转换,而 parseInt 则始终以基数解析字串。

eslint: radix no-new-wrappers

 
  1. const inputValue = '4';

  2. // bad

  3. const val = new Number(inputValue);

  4. // bad

  5. const val = +inputValue;

  6. // bad

  7. const val = inputValue >> 0;

  8. // bad

  9. const val = parseInt(inputValue);

  10. // good

  11. const val = Number(inputValue);

  12. // good

  13. const val = parseInt(inputValue, 10);

布尔值:

eslint: no-new-wrappers

 
  1. const age = 0;

  2. // bad

  3. const hasAge = new Boolean(age);

  4. // good

  5. const hasAge = Boolean(age);

  6. // best

  7. const hasAge = !!age;

命名规则 Naming Conventions

1. 避免使用单字母名称。使你的命名具有描述性。

eslint: id-length

 
  1. // bad

  2. function q() {

  3. // ...

  4. }

  5. // good

  6. function query() {

  7. // ...

  8. }

2. 当命名对象,函数和实例时使用驼峰式命名。

eslint: camelcase jscs: requireCamelCaseOrUpperCaseIdentifiers

 
  1. // bad

  2. const OBJEcttsssss = {};

  3. const this_is_my_object = {};

  4. function c() {}

  5. // good

  6. const thisIsMyObject = {};

  7. function thisIsMyFunction() {}

3. 当命名构造函数或类的时候使用 PascalCase 式命名,(注:即单词首字母大写)。

eslint: new-cap

 
  1. // bad

  2. function user(options) {

  3.   this.name = options.name;

  4. }

  5. const bad = new user({

  6.   name: 'nope',

  7. });

  8. // good

  9. class User {

  10.   constructor(options) {

  11.     this.name = options.name;

  12.   }

  13. }

  14. const good = new User({

  15.   name: 'yup',

  16. });

4. 当 导出(export) 一个默认函数时使用驼峰式命名。你的文件名应该和你的函数的名字一致。

 
  1. function makeStyleGuide() {

  2. // ...

  3. }

  4. export default makeStyleGuide;

5. 当导出一个构造函数 / 类 / 单例 / 函数库 / 纯对象时使用 PascalCase 式命名。

 
  1. const AirbnbStyleGuide = {

  2.   es6: {

  3.     },

  4. };

  5. export default AirbnbStyleGuide;

存取器 Accessors

属性的存取器函数不是必须的。

1. 別使用 JavaScript 的 getters/setters,因为它们会导致意想不到的副作用,而且很难测试,维护和理解。相反,如果要使用存取器函数,使用 getVal() 及 setVal(‘hello’)。

 
  1. // bad

  2. class Dragon {

  3.   get age() {

  4.     // ...

  5.   }

  6.   set age(value) {

  7.     // ...

  8.   }

  9. }

  10. // good

  11. class Dragon {

  12.   getAge() {

  13.     // ...

  14.   }

  15.   setAge(value) {

  16.     // ...

  17.   }

  18. }

2. 如果属性/方法是一个 boolean, 使用 isVal() 或 hasVal() 方法。

 
  1. // bad

  2. if (!dragon.age()) {

  3.   return false;

  4. }

  5. // good

  6. if (!dragon.hasAge()) {

  7.   return false;

  8. }

完结

原文https://mp.weixin.qq.com/s/AEYqExcDdFteHymXK82SMg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值