JavaScript风格指南

References

  1. 所有的赋值都用 const,避免使用 var

Why? 因为这个确保你不会改变你的初始值,重复引用会导致bug和代码难以理解

  1. 如果一定要对参数重新赋值,就用 let , 而不是 var

Why? 因为let是块级作用域,而var是函数级作用域

  1. let / const 都是块级作用域

Objects

  1. 使用字面量创建对象

// bad
const item = new Object();

// good
const item = {};

  1. 用对象方法简写

// bad
const atom = {
value: 1,

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

// good
const atom = {
value: 1,

// 对象的方法

  addValue(value) {
   return atom.value + value;   }, };
  1. 用属性值缩写

const lukeSkywalker = ‘Luke Skywalker’;

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

// good
const obj = { lukeSkywalker, };

  1. 不要直接调用Object.prototype上的方法,如 hasOwnProperty, propertyIsEnumerable, isPrototypeOf

Why? 在一些有问题的对象上, 这些方法可能会被屏蔽掉 - 如:{ hasOwnProperty: false } -
或这是一个空对象Object.create(null)

// bad
console.log(object.hasOwnProperty(key));

// good
console.log(Object.prototype.hasOwnProperty.call(object,
key));

// best
const has = Object.prototype.hasOwnProperty; // 在模块作用内做一次缓存 /*
or */ import has from ‘has’; // https://www.npmjs.com/package/has //

console.log(has.call(object, key));

  1. 对象浅拷贝时,更推荐使用拓展运算符[…],而不是Object.assign。获取对象指定的几个属性时,用对象的rest解构运算符较好

// very bad
const original = { a: 1, b: 2 }; const copy =
Object.assign(original, { c: 3 }); // this mutates original ಠ_ಠ
delete copy.a; // so does this

// bad
const original = { a: 1, b: 2 }; const copy = Object.assign({},
original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }

// good
es6扩展运算符 … const original = { a: 1, b: 2 }; // 浅拷贝 const
copy = { …original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }

// rest 赋值运算符
const { a, …noA } = copy; // noA => { b: 2, c: 3 }

Arrays

  1. 用字面量赋值

// bad
const items = new Array();

// good
const items = [];

  1. 用拓展运算符做数组浅拷贝

// 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. 用…运算符而不是Array.from来将一个可迭代的对象转换成数组

const foo = document.querySelectorAll(’.foo’);

// good
const nodes = Array.from(foo);

// best
const nodes = […foo];

Destructuring

  1. 用对象的解构赋值来获取和使用对象某个或多个属性值

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

  1. 用数组结构

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

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

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

Strings

  1. 对string 用单引号
  2. 超过100个字符的字符串不应该用string串联成多行

Why? 被折断的字符串工作起来是糟糕的而且使得代码更不易被搜索。

  1. 用字符串模板而不是字符串拼接来组织可编程字符串

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

  1. 永远不要在字符串中用eval()。
  2. 不要使用不必要的转义字符。

Functions

  1. 用命名函数表达式而不是函数声明。
    函数表达式:const func = function(){}
    函数声明:function func(){}

// bad
function foo() { // … }

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

// good
// lexical name distinguished from the variable-referenced invocation(s)
// 函数表达式名和声明的函数名是不一样的
const short = function
longUniqueMoreDescriptiveLexicalFoo() { // … };

  1. 不要使用arguments,用rest语法…代替。

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

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

  1. 把默认参数赋值放在最后

// bad
function handleThings(opts = {}, name) { // … }

// good
function handleThings(name, opts = {}) { // … }

  1. 不要对参数重新赋值

// 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) { // … }

Arrow Functions

  1. 当你一定要用函数表达式(在回调函数里)的时候就用箭头表达式吧

Why? 他创建了一个this的当前执行上下文的函数的版本,这通常就是你想要的;而且箭头函数是更简洁的语法
Why? 什么时候不用箭头函数:如果你有一个相当复杂的函数,你可能会把这个逻辑移出到他自己的函数声明里。

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

Classes & Constructors

  1. 常用 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; } }

  1. 用extend实现继承

Why? 它是一种内置的方法来继承原型功能而不打破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]; } }

Modules

  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;

  1. 不要用import 通配符,就是*这种方式

// bad
import * as AirbnbStyleGuide from ‘./AirbnbStyleGuide’;

// good
import AirbnbStyleGuide from ‘./AirbnbStyleGuide’;

  1. 不要导出可变的东西

Why? 变化通常都是需要避免,特别是当你要输出可变的绑定。虽然在某些场景下可能需要这种技术,但总的来说应该导出常量。

// bad
let foo = 3; export { foo }

// good
const foo = 3; export { foo }

  1. 在一个单一导出模块里,用export default 更好

// bad
export function foo() {}

// good
export default function foo() {}

Iterators and Generators

  1. 不要用遍历器。用 JavaScript 高级函数代替for-in / for -of 。

Why? 用数组的这些迭代方法: map() / every() / filter() / find() / findIndex() / reduce() / some() / … , 用对象的这些方法 Object.keys() / Object.values() / Object.entries() 去产生一个数组, 这样你就能去遍历对象了。

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;

// bad
const increasedByOne = []; for (let i = 0; i < numbers.length;
i++) { increasedByOne.push(numbers[i] + 1); }

// good
const increasedByOne = []; numbers.forEach(num =>
increasedByOne.push(num + 1));

// best
(keeping it functional) const increasedByOne = numbers.map(num
=> num + 1);

  1. generator 不建议用,因为在es5上支持不好

Variables

  1. const / let 就不多说了
  2. 不要使用一元自增自减运算符(++,–)

Why? 根据eslint文档,一元增量和减量语句受到自动分号插入的影响,并且可能会导致应用程序中的值递增或递减的无声错误。 使用num +> = 1而不是num ++语句来表达你的值也是更有表现力的。 禁止一元增量和减量语句还会阻止您无意地预增/预减值,这也会导致程序出现意外行为。

Comparison Operators & Equality

  1. 用 === 和 !== 而不是 == 和 !=
  2. 布尔值用缩写,数字和字符串要明确比较对象

// bad
if (isValid === true) { // … }

// good
if (isValid) { // … }

// bad
if (name) { // … }

// good
if (name !== ‘’) { // … }

// bad
if (collection.length) { // … }

// good
if (collection.length > 0) { // … }

  1. 三元表达式不应该嵌套,通常是单行表达式
  2. 如果if 语句中总是需要用return,那后续的else就不需要写了。if块中包含return,它后面的else if 块中也包含了return ,这个时候就可以把return 分到多个 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; } }

Comments

  1. 在你的注释前使用FIXME 或TODO前缀,这有助于其他开发人员快速理解你指出的需要重新访问的问题,或者建议需要实现的问题的解决方案,这些不同于常规注释,他们是可操作的。动作是FIXME:需要计算出来 TODO :需要实现
  2. // FIXME : 给问题做注释

class Calculator extends Abacus { constructor() {
super();

// FIXME: shouldn't use a global here
total = 0;   } }
  1. 用// TODO: 去注释问题的解决方案

class Calculator extends Abacus { constructor() {
super();

// TODO: total should be configurable by an options param
this.total = 0;   } }

Naming Conventions

  1. 用小驼峰式命名对象/函数/实例
  2. 用大驼峰式命名类
  3. 不要用前置或后置下划线
  4. 不要保存使用this,用箭头函数或函数绑定

// bad
function foo() { const self = this; return function () {
console.log(self); }; }

// bad
function foo() { const that = this; return function () {
console.log(that); }; }

// good
function foo() { return () => {
console.log(this); }; }

  1. export default 导出模块A,则这个文件名也叫A.*,import 时候的参数也叫A,大小写一致。
  2. 当export default一个函数时,函数名用小驼峰,文件名需要和函数名一致
  3. 当export一个结构体/类/单例/函数库/对象 时用大驼峰
  4. 大写字母设置静态变量,需要满足三个条件

a . 导出变量
b . 是const定义的
c . 变量可信且他的子属性都是不能改变的

文章参考自:https://github.com/lin-123/javascript#目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值