一、javascript代码规范
-
变量
1.1 一直使用
const
来声明变量,如果不这样做就会产生全局变量。我们需要避免全局命名空间的污染。地球队长已经警告过我们了。(译注:全局,global 亦有全球的意思。地球队长的责任是保卫地球环境,所以他警告我们不要造成「全球」污染。)// bad superPower = new SuperPower(); // good const superPower = new SuperPower();
1.2 使用 const、let 声明变量,而不使用 var。
-
数组
2.1 使用字面值创建数组。
// bad const items = new Array(); // good const items = [];
2.2 向数组添加元素时使用 Arrary#push 替代直接赋值。
const someStack = []; // bad someStack[someStack.length] = 'abracadabra'; // good someStack.push('abracadabra');
2.3 使用拓展运算符
...
复制数组。// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
2.4 使用 Array#from 把一个类数组对象转换成数组。
const foo = document.querySelectorAll('.foo'); const nodes = Array.from(foo);
-
字符串
3.1 字符串使用单引号
''
3.2 字符串过长时,使用+连接字符串
过度使用字串连接符号可能会对性能造成影响。// 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.';
3.3 程序化生成字符串时,使用模板字符串代替字符串连接。
// 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}?`; }
-
函数
4.1 永远不要把参数命名为
arguments
。这将取代原来函数作用域内的arguments
对象。// bad function nope(name, options, arguments) { // ...stuff... } // good function yup(name, options, args) { // ...stuff... }
4.2 不要使用
arguments
。可以选择 rest 语法...
替代。为什么?使用
...
能明确你要传入的参数。另外 rest 参数是一个真正的数组,而arguments
是一个类数组。// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
4.3 直接给函数的参数指定默认值,不要使用一个变化的函数参数。
// 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 = {}) { // ... }
4.4 除非参数过多,不然不要传入一个对象
// bad function handleThings(user) { // ... return user.username == '' } // good function handleThings(username) { // ... return username == '' }
-
箭头函数
5.1 当你必须使用函数表达式(或传递一个匿名函数)时,使用箭头函数符号。
为什么?因为箭头函数创造了新的一个
this
执行环境,通常情况下都能满足你的需求,而且这样的写法更为简洁。为什么不?如果你有一个相当复杂的函数,你或许可以把逻辑部分转移到一个函数声明上。
// bad [1, 2, 3].map(function (x) { return x * x; }); // good [1, 2, 3].map((x) => { return x * x; });
5.2 如果一个函数适合用一行写出并且只有一个参数,那就把花括号、圆括号和
return
都省略掉。如果不是,那就不要省略。为什么?语法糖。在链式调用中可读性很高。
为什么不?当你打算回传一个对象的时候。
// good [1, 2, 3].map(x => x * x); // good [1, 2, 3].reduce((total, n) => { return total + n; }, 0);
-
属性
6.1 使用
.
来访问对象的属性。const luke = { jedi: true, age: 28, }; // bad const isJedi = luke['jedi']; // good const isJedi = luke.jedi;
6.2 当通过变量访问属性时使用中括号
[]
。const luke = { jedi: true, age: 28, }; function getProp(prop) { return luke[prop]; } const isJedi = getProp('jedi');
-
解构
7.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}`; }
7.2 对数组使用解构赋值。
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
7.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);
-
比较运算符 & 等号
8.1
优先使用
=== 和 !==
而不是
== 和 !=
8.2 条件表达式例如 if 语句通过抽象方法
ToBoolean
强制计算它们的表达式并且总是遵守下面的规则:- 对象 被计算为
true
-
Undefined
被计算为false
-
Null
被计算为false
-
Boolean
被计算为true
或false
- 数字 如果是
+0
、-0
、或NaN
被计算为false
, 否则为true
- 字符串 如果是空字符串
''
被计算为false
,否则为true
if ([0]) { // true // An array is an object, objects evaluate to true }
- 对象 被计算为
-
注释
9.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; }
9.2 使用
//
作为单行注释。在评论对象上面另起一行使用单行注释。在注释前插入空行。9.3
//
符号后添加一个空格9.4 方法使用jsdoc的方式注释
-
分号
10.1 匿名方法后必须使用分号
代码压缩后如果多个匿名方法压缩在一起会变成代码错误。
-
命名规制
11.1 避免单字母命名。命名应具备描述性。
// bad function q() { // ...stuff... } // good function query() { // ..stuff.. }
11.2 使用驼峰式命名对象、函数和实例。
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
11.3 使用帕斯卡式命名构造函数或类。
// 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', });
-
原型链
12.1 尽量避免覆盖原型链的方式修改javascript基础对象,如String、Date
-
模块
13.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;
二、React/JSX
-
Declaration 声明模块
使用
class extends React.Component
而不是React.createClass
,除非你有充足的理由来使用这些方法.// bad const Listing = React.createClass({ // ... render() { return <div>{this.state.hello}</div>; } }); // good class Listing extends React.Component { // ... render() { return <div>{this.state.hello}</div>; } }
-
Alignment 代码对齐
2.1 遵循以下的JSX语法缩进/格式. eslint:
react/jsx-closing-bracket-location
// bad <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // good, 有多行属性的话, 新建一行关闭标签 <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // 若能在一行中显示, 直接写成一行 <Foo bar="bar" /> // 子元素按照常规方式缩进 <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo>
-
Quotes 单引号还是双引号
3.1 对于JSX属性值总是使用双引号(
"
), 其他均使用单引号('
).
为什么? HTML属性也是用双引号, 因此JSX的属性也遵循此约定.
-
Spacing 空格
4.1 总是在自动关闭的标签前加一个空格,正常情况下也不需要换行. eslint:
no-multi-spaces
,react/jsx-space-before-closing
// bad <Foo/> // very bad <Foo /> // bad <Foo /> // good <Foo />
4.2 不要在JSX
{}
引用括号里两边加空格. eslint:react/jsx-curly-spacing
// bad <Foo bar={ baz } /> // good <Foo bar={baz} />
-
Props 属性
5.1 JSX属性名使用骆驼式风格
camelCase
.// bad <Foo UserName="hello" phone_number={12345678} /> // good <Foo userName="hello" phoneNumber={12345678} />
5.2 对于所有非必须的属性,总是手动去定义
defaultProps
属性.为什么? propTypes 可以作为模块的文档说明, 并且声明 defaultProps 的话意味着阅读代码的人不需要去假设一些默认值。更重要的是, 显示的声明默认属性可以让你的模块跳过属性类型的检查.
// bad function SFC({ foo, bar, children }) { return <div>{foo}{bar}{children}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node, }; // good function SFC({ foo, bar }) { return <div>{foo}{bar}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, }; SFC.defaultProps = { bar: '', children: null, };
-
Parentheses 括号
6.1 将多行的JSX标签写在
()
里. eslint:react/wrap-multilines
// bad render() { return <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent>; } // good render() { return ( <MyComponent className="long body" foo="bar"> <MyChild /> </MyComponent> ); } // good, 单行可以不需要 render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
-
Tags 标签
7.1 对于没有子元素的标签来说总是自己关闭标签. eslint:
react/self-closing-comp
// bad <Foo className="stuff"></Foo> // good <Foo className="stuff" />
7.2 如果模块有多行的属性, 关闭标签时新建一行. eslint: react/jsx-closing-bracket-location
// bad
<Foo
bar="bar"
baz="baz" />
// good
<Foo
bar="bar"
baz="baz"
/>
-
Methods 函数
8.1 当在
render()
里使用事件处理方法时,提前在构造函数里把this
绑定上去. eslint:react/jsx-no-bind
// bad class extends React.Component { onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv.bind(this)} /> } } // good class extends React.Component { constructor(props) { super(props); this.onClickDiv = this.onClickDiv.bind(this); } onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv} /> } } // good class extends React.Component { constructor(props) { super(props); } onClickDiv = () => { // do stuff } render() { return <div onClick={this.onClickDiv} /> } }
8.2 在
render
方法中总是确保return
返回值. eslint:react/require-render-return
// bad render() { (<div />); } // good render() { return (<div />); }
-
Ordering React 模块生命周期
主要规范组件内部方法的定义顺序。
Es6 class 定义规范:
static 方法 constructor getChildContext componentWillMount componentDidMount componentWillReceiveProps shouldComponentUpdate componentWillUpdate componentDidUpdate componentWillUnmount clickHandlers + eventHandlers 如 onClickSubmit() 或 onChangeDescription() getter methods for render 如 getSelectReason() 或 getFooterContent() render methods 如 renderNavigation() 或 renderProfilePicture() render
以 Es6 Class 定义的组件为例
class Person extends React.Component { static defaultProps = {} static propTypes = {} // 构造函数 constructor (props) { super(props); // 定义 state this.state = { smiling: false }; } // 生命周期方法 componentWillMount () {} componentDidMount () {} componentWillUnmount () {} // getters and setters get attr() {} // handlers handleClick = () => {} // render renderChild() {} render () {} }
网友评论