前端开发代码规范(三)

2022-07-31  本文已影响0人  Yinzhishan

JavaScript编码规范

1.类型

1.1基本类型: 直接存取基本类型。

const foo = 1;
let bar = foo;
bar = 9;

console.log(foo, bar); // => 1, 9

1.2复杂类型: 通过引用的方式存取复杂类型

const foo = [1, 2];
const bar = foo;

bar[0] = 9;

console.log(foo[0], bar[0]); // => 9, 9

2.引用

2.1 [强制] 对所有的引用使用 const ;不要使用 var

为什么?这能确保你无法对引用重新赋值,也不会导致出现 bug 或难以理解。

// bad
var a = 1;
var b = 2;

// good
const a = 1;
const b = 2;

2.2 [强制] 需要可变动的引用,使用 let 代替 var

为什么?因为 letconst是块级作用域,而 var 是函数作用域。
constlet 只存在于它们被定义的区块内。

{
  let a = 1;
  const b = 1;
}
console.log(a); // ReferenceError
console.log(b); // ReferenceError
// bad
var count = 1;
if (true) {
  count += 1;
}

// good, use the let.
let count = 1;
if (true) {
  count += 1;
}

3.对象

3.1 [强制] 禁止使用[保留字]作为属性名

因为在IE8及以下版本存在问题,使用同义词替换它

// bad
const item = {
  class: 'dark'
};

// good
const item = {
  type: 'dark'
};

3.2 [强制] 禁止在对象的最后一个属性值后添加,

IE6和IE7下会存在js报错(同上)

// bad
const item = {
  type: 'dark',
  element: 'flame',
};

// good
const item = {
  type: 'dark',
  element: 'flame'
};

3.3 [强制] 使用字面值创建对象

// bad
const item = new Object();

// good
const item = {};

3.4 [强制] 使用对象方法的简写

// bad
const atom = {
  value: 1,

  addValue: function (value) {
    return atom.value + value;
  },
};

// good
const atom = {
  value: 1,

  addValue(value) {
    return atom.value + value;
  },
};

3.5 [强制] 使用对象属性值的简写

const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  lukeSkywalker: lukeSkywalker,
};

// good
const obj = {
  lukeSkywalker,
};

3.6 [推荐] 在对象属性声明前把简写的属性分组

const anakinSkywalker = 'Anakin Skywalker';
const lukeSkywalker = 'Luke Skywalker';

// bad
const obj = {
  episodeOne: 1,
  twoJedisWalkIntoACantina: 2,
  lukeSkywalker,
  episodeThree: 3,
  mayTheFourth: 4,
  anakinSkywalker,
};

// good
const obj = {
  lukeSkywalker,
  anakinSkywalker,
  episodeOne: 1,
  twoJedisWalkIntoACantina: 2,
  episodeThree: 3,
  mayTheFourth: 4,
};

4.数组

4.1 [强制] 使用字面量创建数组

// bad
const item = new Array();

// good
const item = [];

4.2 [强制] 向数组末尾增加元素时,使用 Array.push() 代替直接赋值

let magicBook = [];

// bad
magicBook[magicBook.length] = 'Expelliarmus';

// good
magicBook.push('Expelliarmus');

4.3 [强制] 浅拷贝(shallow copy)数组时,使用 Array.slice() 或拓展运算符 ... 复制数组

浅拷贝:由于对象和数组在赋值的时候都是引用传递,赋值的时候只是传递一个指针(见1.类型),浅拷贝的数组中的对象依旧是引用。

深拷贝(deep copy): 可以使用jqueryjQuery.extend 或者 npm的 deep*copy 方法等。

let items = [{ id: 1 },{ id: 2}];
const len = items.length;
const itemsCopy = [];
let i;

// bad
for (i = 0; i < len; i++) {
  itemsCopy[i] = items[i];
}

// good
itemsCopy = items.slice();

// good
const itemsCopy = [...items];

//is shallow copy?
items[0] == itemsCopy[0]; // => true 为浅拷贝

4.4 [推荐] 使用 Array.from() 把一个类数组对象转换成数组。

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

5.字符串

5.1 [建议] 使用单引号包裹字符串

// bad
const name = "Harry Potter";

// good
const name = 'Harry Potter';

5.2[强制] 程序化生成字符串时,使用模板字符串代替字符串连接

// bad
function sayHi(name) {
  return 'How are you, ' + name + '?';
}

// bad
function sayHi(name) {
  return ['How are you, ', name, '?'].join();
}

// good
function sayHi(name) {
  return `How are you, ${name}?`;
}

6.函数

6.1 [强制] 禁止在非函数代码块中(如 if while)声明函数

// bad
if (flag) {
  function castSpell(){
    // do something...
  }
}

// good
function castAvada() {
  return 'Avada Kedavra';
}

let castSpell;

if (flag) {
  castSpell = castAvada;
}

6.2 [强制] 禁止把参数名命名为arguments,会取代函数中的arguments

// bad
function nope(name, options, arguments) {
  // ...stuff...
}

// good
function yup(name, options, args) {
  // ...stuff...
}

6.3 [推荐] 不要使用 arguments。可以选择 rest 语法 ... 替代

为什么?使用 ... 能明确你要传入的参数。另外 rest 参数是一个真正的数组,而 arguments 是一个类数组。

// bad
function concatenateAll() {
  const args = Array.prototype.slice.call(arguments);
  return args.join('');
}

// good
function concatenateAll(...args) {
  return args.join('');
}

6.4 [强制] 禁止使用全局严格模式

// yes
function handel() {
  "use strict";
}

// no
"use strict";
function handel() {

}

6.5 [推荐] 使用函数声明代替函数表达式。

为什么?因为函数声明是可命名的,所以他们在调用栈中更容易被识别。此外,函数声明会把整个函数提升(hoisted),而函数表达式只会把函数的引用变量名提升。这条规则使得箭头函数可以取代函数表达式。

// bad
const foo = function () {
};

// good
function foo() {
}

6.6 [推荐] 直接给函数的参数指定默认值,不要使用一个变化的函数参数。

// really bad
function handleThings(opts) {
  // 不!我们不应该改变函数参数。
  // 更加糟糕: 如果参数 opts 是 false 的话,它就会被设定为一个对象。
  // 但这样的写法会造成一些 Bugs。
  //(译注:例如当 opts 被赋值为空字符串,opts 仍然会被下一行代码设定为一个空对象。)
  opts = opts || {};
  // ...
}

// still bad
function handleThings(opts) {
  if (opts === void 0) {
    opts = {};
  }
  // ...
}

// good
function handleThings(opts = {}) {
  // ...
}

6.7 [推荐] 箭头函数代替function

// 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;
});

如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和 return 都省略掉。如果不是,那就不要省略。

// good
[1, 2, 3].map(x => x * x);

// good
[1, 2, 3].reduce((total, n) => {
  return total + n;
}, 0);

7.属性

7.1 [强制] 使用 . 来访问对象的属性

const luke = {
  jedi: true,
  age: 28,
};

// bad
const isJedi = luke['jedi'];

// good
const isJedi = luke.jedi;

7.2 [强制] 当通过变量访问属性时使用中括号 []

const luke = {
  jedi: true,
  age: 28,
};

function getProp(prop) {
  return luke[prop];
}

const isJedi = getProp('jedi');

8.变量

8.1 [强制] 使用 let const 替换代码中的var,代码中不要出现魔幻数字,用const提前声明这些常量

// bad
var a = 10;
var arr = [1,2,3];
superPower = new SuperPower();

// good
const a = 10;
let arr = [1,2,3];
const superPower = new SuperPower();

8.2 [强制] 如果需要要声明一个全局变量,必须使用window.

// bad
spell = 'Expelliarmus';

// good
window.spell = 'Expelliarmus';

9.解构

9.1 [推荐] 使用解构存取和使用多属性对象。

为什么?因为解构能减少临时引用属性。

// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;

  return `${firstName} ${lastName}`;
}

// good
function getFullName(obj) {
  const { firstName, lastName } = obj;
  return `${firstName} ${lastName}`;
}

// best
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`;
}

9.2 [推荐] 对数组使用解构赋值。

const arr = [1, 2, 3, 4];

// bad
const first = arr[0];
const second = arr[1];

// good
const [first, second] = arr;

9.3 [推荐] 需要回传多个值时,使用对象解构,而不是数组解构。

为什么?增加属性或者改变排序不会改变调用时的位置。

// bad
function processInput(input) {
  // then a miracle occurs
  return [left, right, top, bottom];
}

// 调用时需要考虑回调数据的顺序。
const [left, __, top] = processInput(input);

// good
function processInput(input) {
  // then a miracle occurs
  return { left, right, top, bottom };
}

// 调用时只选择需要的数据
const { left, right } = processInput(input);

10.构造器

10.1 [推荐] 总是使用 class。避免直接操作 prototype

为什么? 因为 class 语法更为简洁更易读。

// 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;
  }
}

10.2 [推荐] 使用 extends 继承。

为什么?因为 extends 是一个内建的原型继承方法并且不会破坏 instanceof

// 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];
  }
}

10.3 [推荐] 方法可以返回 this 来帮助链式调用。

// bad
Jedi.prototype.jump = function() {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
};

const luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined

// good
class Jedi {
  jump() {
    this.jumping = true;
    return this;
  }

  setHeight(height) {
    this.height = height;
    return this;
  }
}

const luke = new Jedi();

luke.jump()
  .setHeight(20);

11.模块

11.1 [推荐] 总是使用模组 (import/export) 而不是其他非标准模块系统。

为什么?模块就是未来,让我们开始迈向未来吧。

// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;

// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;

// best
import { es6 } from './AirbnbStyleGuide';
export default es6;

11.2 [强制] 不要使用通配符*

为什么?这样能确保你只有一个默认 export

// bad
import * as AirbnbStyleGuide from './AirbnbStyleGuide';

// good
import AirbnbStyleGuide from './AirbnbStyleGuide';

11.3 [推荐] 不要从 import 中直接 export

为什么?虽然一行代码简洁明了,但让 importexport 各司其职让事情能保持一致。

// bad
// filename es6.js
export { es6 as default } from './airbnbStyleGuide';

// good
// filename es6.js
import { es6 } from './AirbnbStyleGuide';
export default es6;

12.Iterators and Generators

12.1 [推荐] 不要使用 iterators。使用高阶函数例如 map()reduce() 替代 for*of

为什么?这加强了我们不变的规则。处理纯函数的回调值更易读,这比它带来的副作用更重要。

const numbers = [1, 2, 3, 4, 5];

// bad
let sum = 0;
for (let num of numbers) {
  sum += num;
}

sum === 15;

// good
let sum = 0;
numbers.forEach((num) => sum += num);
sum === 15;

// best (use the functional force)
const sum = numbers.reduce((total, num) => total + num, 0);
sum === 15;

12.2 现在还不要使用generators

为什么?因为它们现在还没法很好地编译到 ES5。

13比较运算符和等号

13.1 [强制] 优先使用 ===!== 而不是 ==!=.

13.2 [推荐] 使用简写。

// bad
if (name !== '') {
  // ...stuff...
}

// good
if (name) {
  // ...stuff...
}

// bad
if (collection.length > 0) {
  // ...stuff...
}

// good
if (collection.length) {
  // ...stuff...
}

13.3条件表达式的强制类型转换遵循以下规则:

if([0]) {
  // true 因为数组是对象,对象被计算为true
}

if([]){
 // true 因为数组是对象,对象被计算为true
}

14.代码块

14.1 [强制] 使用大括号包裹所有的多行代码块。

// bad
if (test)
  return false;

// good
if (test) return false;

// good
if (test) {
  return false;
}

// bad
function() { return false; }

// good
function() {
  return false;
}

14.2 [强制] 如果通过 ifelse 使用多行代码块,把 else 放在 if 代码块关闭括号的同一行。

// bad
if (test) {
  thing1();
  thing2();
}
else {
  thing3();
}

// good
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}

15.注释

15.1 [强制] 使用/** ... */ 作为多行注释。包含描述、指定所有参数和返回值的类型和值。

// bad
// make() returns a new element
// based on the passed in tag name
//
// @param {String} tag
// @return {Element} element
function make(tag) {

  // ...stuff...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed in tag name
 *
 * @param {String} tag
 * @return {Element} element
 */
function make(tag) {

  // ...stuff...

  return element;
}

15.2 [强制] 使用 // 作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。

// bad
const active = true;  // is current tab

// good
// is current tab
const active = true;

// bad
function getType() {
  console.log('fetching type...');
  // set the default type to 'no type'
  const type = this._type || 'no type';

  return type;
}

// good
function getType() {
  console.log('fetching type...');

  // set the default type to 'no type'
  const type = this._type || 'no type';

  return type;
}

15.3 [推荐] 给注释增加 FIXMETODO 的前缀。

这可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 FIXME ** need to figure this out 或者 TODO ** need to implement

使用 // FIXME: 标注问题。

class Calculator {
  constructor() {
    // FIXME: shouldn't use a global here
    total = 0;
  }
}

使用 // TODO: 标注问题的解决方式。

class Calculator {
  constructor() {
    // TODO: total should be configurable by an options param
    this.total = 0;
  }
}

16.空白

16.1 [强制] 使用 2 个空格作为缩进。

// bad
function() {
∙∙∙∙const name;
}

// bad
function() {
∙const name;
}

// good
function() {
∙∙const name;
}

16.2 [强制] 在花括号前放一个空格。

// bad
function test(){
  console.log('test');
}

// good
function test() {
  console.log('test');
}

// bad
dog.set('attr',{
  age: '1 year',
  breed: 'Bernese Mountain Dog',
});

// good
dog.set('attr', {
  age: '1 year',
  breed: 'Bernese Mountain Dog',
});

16.3 [强制] 在控制语句(ifwhile 等)的小括号前放一个空格。在函数调用及声明中,不在函数的参数列表前加空格。

// bad
if(isJedi) {
  fight ();
}

// good
if (isJedi) {
  fight();
}

// bad
function fight () {
  console.log ('Swooosh!');
}

// good
function fight() {
  console.log('Swooosh!');
}

16.4 [强制] 使用空格把运算符隔开。

// bad
const x=y+5;

// good
const x = y + 5;

16.5 [强制] 在文件末尾插入一个空行。

// bad
(function(global) {
  // ...stuff...
})(this);

// bad
(function(global) {
  // ...stuff...
})(this);↵
↵

// good
(function(global) {
  // ...stuff...
})(this);↵

16.6 [推荐] 在使用长方法链时进行缩进。使用前面的点 . 强调这是方法调用而不是新语句。

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

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

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

// bad
const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

// good
const leds = stage.selectAll('.led')
    .data(data)
  .enter().append('svg:svg')
    .classed('led', true)
    .attr('width', (radius + margin) * 2)
  .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

16.7 [推荐] 在块末和新语句前插入空行。

// bad
if (foo) {
  return bar;
}
return baz;

// good
if (foo) {
  return bar;
}

return baz;

// bad
const obj = {
  foo() {
  },
  bar() {
  },
};
return obj;

// good
const obj = {
  foo() {
  },

  bar() {
  },
};

return obj;

17.逗号

17.1 [强制] 在变量或表达式后面添加逗号,不要出现逗号,在前

// bad
const hero = {
    firstName: 'Ada'
  , lastName: 'Lovelace'
  , birthYear: 1815
  , superPower: 'computers'
};

// good
const hero = {
  firstName: 'Ada',
  lastName: 'Lovelace',
  birthYear: 1815,
  superPower: 'computers',
};

17.2 [强制] 去掉不必要的逗号,这在IE67下会出现怪异行为。

const hero = {
  name:'hongxin',
  age:18,
}

const heros = [
  'Batman',
  'Superman',
]

18.分号

18.1 [推荐] 每条语句必须加分号。

// bad
(function() {
  const name = 'Skywalker'
  return name
})()

// good
(() => {
  const name = 'Skywalker';
  return name;
})();

// good (防止函数在两个 IIFE 合并时被当成一个参数)
;(() => {
  const name = 'Skywalker';
  return name;
})();

19.类型转换

19.1 [推荐] 字符串转换

//  => this.reviewScore = 9;

// bad
const totalScore = this.reviewScore + '';

// good
const totalScore = String(this.reviewScore);

19.2 [推荐] 布尔转换

const age = 0;

// bad
const hasAge = new Boolean(age);

// good
const hasAge = Boolean(age);

// good
const hasAge = !!age;

19.3 [强制] 使用parseInt转换数字时总是带上转换基数

// bad
parseInt('0x10'); // => 16

parseInt('09'); // => 0 (ie8下, ie9+及chrome为9)

// good
parseInt('09',10); // => 9

19.4 [谨慎] 小心使用位操作运算符。

数字会被当成 64 位值,但是位操作运算符总是返回 32 位的整数。位操作处理大于 32 位的整数值时还会导致意料之外的行为。最大的 32 位整数是 2,147,483,647

2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> *2147483648
2147483649 >> 0 //=> *2147483647

20.命名规则

20.1 [强制] 避免单字母命名。命名应具备描述性。

// bad
function q() {
  // ...stuff...
}

// good
function query() {
  // ..stuff..
}

20.2 [强制] 以驼峰形式命名变量、函数和实例

变量和实例应尽量以名词为主,函数名尽量以动词+名词组合,返回布尔值的函数尽量以is、has打头

// good
const communityList = [];

function collectShells(){
  return shells;
}

function isAnimal(){
  return bool;
}

20.3 [强制] 常量必须全部大写,多个单词以下划线分隔

const LANEHUB = 10;
const LANEHUB_JAVASCRIPT = 100;

20.4 [强制] 使用帕斯卡式命名(大驼峰)构造函数或类。

当你导出单例、函数库、空对象时使用帕斯卡式命名

// 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',
});

20.5 [强制] 不要使用下划线 _ 结尾或开头来命名属性和方法。

// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';
this._firstName = 'Panda';

// good
this.firstName = 'Panda';

20.6 [强制] 如果你的文件只输出一个类,那你的文件名必须和类名完全保持一致。

// file contents
class CheckBox {
  // ...
}
export default CheckBox;

// in some other file
// bad
import CheckBox from './checkBox';

// bad
import CheckBox from './check_box';

// good
import CheckBox from './CheckBox';

21.ECMAScript 规范 [学习]

ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准,于2015年6月批准通过。ECMAScript6的目标,是使得JavaScript语言可以用来编写复杂的大型应用程序,成为企业级开发语言。让代码更加准确,更易于阅读。
—— 推荐地址

JavaScript最强势的监工-正在迈向ES8,所以让我们来了解下ES7 and ES8(官方称ES2016 and ES2017),幸运的是,他们比ES6标准功能少好多好多
—— 推荐地址

上一篇下一篇

猜你喜欢

热点阅读