# es6-coding-style
**Repository Path**: golong/es6-coding-style
## Basic Information
- **Project Name**: es6-coding-style
- **Description**: ECMAScript 2015 Coding Style -- 广发证券前端团队
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-08-06
- **Last Updated**: 2020-12-18
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ECMAScript6 编码规范--广发证券前端团队
> 本规范是基于JavaScript规范拟定的,只针对ES6相关内容进行约定
> 如变量命名,是否加分号等约定的请参考JavaScript规范
> 应注意目前的代码转换工具(如Babel,Traceur)不够完善,有些特性须谨慎使用
### [ES6 Coding Style English Version](https://github.com/gf-web/es6-coding-style/blob/master/es6-coding-style-en.md)
## 规范内容
1. [声明 Declarations](#声明)
2. [字符串 Strings](#字符串)
3. [解构 Destructuring](#解构)
4. [数组 Arrays](#数组)
5. [函数 Functions](#函数)
6. [类 Classes](#类)
7. [模块 Modules](#模块)
8. [版权 Copyright](#copyright)
### 声明
- 1.1 变量
> 对于只在当前作用域下有效的变量,应使用`let`来代替`var`
> 对于全局变量声明,采用`var`,但应避免声明过多全局变量污染环境
```js
// 不好
const variables;
const globalObj = null; // 不是常量
let globalObj = null;
for (var i=0; i<5; i++) {
console.log(i);
}
console.log(i); // 4
// 好
let variables;
var globalObj = null;
for (let i=0; i<5; i++) {
console.log(i);
}
console.log(i); // ReferenceError: i is not defined
```
- 1.2 常量
> 对于常量应使用`const`进行声明,命名应遵循字母全大写的通俗约定
> 对于使用 immutable 数据应用`const`进行声明
> 注意: `const`与`let`只在声明所在的块级作用域内有效
```js
// 不好
const someNum = 123;
const AnotherStr = '不变的字符串';
let SOME_ARR = ['不', '变', '数', '组'];
var ANOTHER_OBJ = {
'不变对象': true
};
// 好
const SOME_NUM = 123;
const ANOTHER_STR = '不变的字符串';
const SOME_ARR = ['不', '变', '数', '组'];
const ANOTHER_OBJ = {
'不变对象': true
};
```
#### 字符串
- 2.1 处理多行字符串,使用模板字符串
> 以反引号( ` )标示
> 可读性更强,代码更易编写
> 注意排版引起空格的问题,使用场景为声明HTML模板字符串
```js
// 不好
const tmpl = '
多行字符串
\n' +
'这是换行了。
';
// 好
const tmpl = `多行字符串
这是换行了。
`;
```
- 2.2 处理字符串拼接变量时,使用模板字符串
```js
// 不好
function sayHi(name) {
return 'How are you, ' + name + '?';
}
// 好
function sayHi(name) {
return `How are you, ${name}?`;
}
```
#### 解构
- 3.1 嵌套结构的对象层数不能超过3层
```js
// 不好
let obj = {
'one': [
{
'newTwo': [
{
'three': [
'four': '太多层了,头晕晕'
]
}
]
}
]
};
// 好
let obj = {
'one': [
'two',
{
'twoObj': '结构清晰'
}
]
};
```
- 3.2 解构语句中统一不使用圆括号
```js
// 不好
[(a)] = [11]; // a未定义
let {a:(b)} = {}; // 解析出错
// 好
let [a, b] = [11, 22];
```
- 3.3 对象解构
> 对象解构 元素与顺序无关
> 对象指定默认值时仅对恒等于undefined ( !== null ) 的情况生效
- 3.3.1 若函数形参为对象时,使用对象解构赋值
```js
// 不好
function someFun(opt) {
let opt1 = opt.opt1;
let opt2 = opt.opt2;
console.log(op1);
}
// 好
function someFun(opt) {
let {opt1, opt2} = opt;
console.log(`$(opt1) 加上 $(opt2)`);
}
function someFun({opt1, opt2}) {
console.log(opt1);
}
```
- 3.3.2 若函数有多个返回值时,使用对象解构,不使用数组解构,避免添加顺序的问题
```js
// 不好
function anotherFun() {
const one = 1, two = 2, three = 3;
return [one, two, three];
}
const [one, three, two] = anotherFun(); // 顺序乱了
// one = 1, two = 3, three = 2
// 好
function anotherFun() {
const one = 1, two = 2, three = 3;
return {one, two, three};
}
const {one, three, two} = anotherFun(); // 不用管顺序
// one = 1, two = 2, three = 3
```
- 3.3.3 已声明的变量不能用于解构赋值(语法错误)
```js
// 语法错误
let a;
{a} = {b:123};
```
- 3.4 数组解构
> 数组元素与顺序相关
- 3.4.1 交换变量的值
```js
let x = 1;
let y = 2;
// 不好
let temp;
temp = x;
x = y;
y = temp;
// 好
[x, y] = [y, x]; // 交换变量
```
- 3.4.2 将数组成员赋值给变量时,使用数组解构
```js
const arr = [1,2,3,4,5];
// 不好
const one = arr[0];
const two = arr[1];
// 好
const [one, two] = arr;
```
#### 数组
- 4.1 将类数组(array-like)对象与可遍历对象(如`Set`, `Map`)转为真正数组
> 采用`Array.from`进行转换
```js
// 不好
function foo() {
let args = Array.prototype.slice.call(arguments);
}
// 好
function foo() {
let args = Array.from(arguments);
}
```
- 4.2 数组去重
> 结合`Set`结构与`Array.from`
> 使用indexOf,HashTable等形式,不够简洁清晰
```js
// 好
function deduplication(arr) {
return Array.from(new Set(arr));
}
```
- 4.3 数组拷贝
> 采用数组扩展`...`形式
```js
const items = [1, 2, 3];
// 不好
const len = items.length;
let copyTemp = [];
for (let i=0; i 采用`Array.of`进行转换
```js
// 不好
let arr1 = new Array(2); // [undefined x 2]
let arr2 = new Array(1, 2, 3); // [1, 2, 3]
// 好
let arr1 = Array.of(2); // [2]
let arr2 = Array.of(1, 2, 3); // [1, 2, 3]
```
#### 函数
- 5.1 当要用函数表达式或匿名函数时,使用箭头函数(Arrow Functions)
> 箭头函数更加简洁,并且绑定了this
```js
// 不好
const foo = function(x) {
console.log(foo.name); // 返回'' ,函数表达式默认省略name属性
};
[1, 2, 3].map(function(x) {
return x + 1;
});
var testObj = {
name: 'testObj',
init: function init() {
var _this = this; // 保存定义时的this引用
document.addEventListener('click', function() {
return _this.doSth();
}, false);
},
doSth: function() {
console.log(this.name);
}
};
// 好
const foo = x => {
console.log(foo.name); // 返回'foo'
};
[1, 2, 3].map( x => {
return x + 1;
});
var testObj = {
name: 'testObj',
init: function() {
// 箭头函数自动绑定定义时所在的对象
document.addEventListener('click', () => this.doSth(), false);
},
doSth: function() {
console.log(this.name);
}
};
```
- 5.1.1 箭头函数书写约定
> 函数体只有单行语句时,允许写在同一行并去除花括号
> 当函数只有一个参数时,允许去除参数外层的括号
```js
// 好
const foo = x => x + x; // 注意此处会隐性return x + x
const foo = (x) => {
return x + x; // 若函数体有花括号语句块时须进行显性的return
};
[1, 2, 3].map( x => x * x);
```
- 5.1.2 用箭头函数返回一个对象,应用括号包裹
```js
// 不好
let test = x => {x:x}; // 花括号会变成语句块,不表示对象
// 好
let test = x => ({x:x}); // 使用括号可正确return {x:x}
```
- 5.2 立即调用函数 IIFE
> 使用箭头函数
```js
// 不好
(function() {
console.log('哈');
})();
// 好
(() => {
console.log('哈');
})();
```
- 5.3 不使用 `arguments`, 采用rest语法`...`代替
> rest参数是真正的数组,不需要再转换
> 注意:箭头函数中不能使用`arguments`对象
```js
// 不好
function foo() {
let args = Array.prototype.slice.call(arguments);
return args.join('');
}
// 好
function foo(...args) {
return args.join('');
}
```
- 5.4 函数参数指定默认值
> 采用函数默认参数赋值语法
```js
// 不好
function foo(opts) {
opts = opts || {};// 此处有将0,''等假值转换掉为默认值的副作用
}
// 好
function foo(opts = {}) {
console.log('更加简洁,安全');
}
```
- 5.5 对象中的函数方法使用缩写形式
> 更加简洁
```js
// 不好
const shopObj = {
des: '对象模块写法',
foo: function() {
console.log('对象中的方法');
}
};
// 好
const shopObj = {
des: '对象模块写法',
foo() {
console.log('对象中的方法');
}
};
```
#### 类
- 6.1 类名应使用帕斯卡写法(PascalCased)
```js
class SomeClass {
}
```
- 6.1.1 类名与花括号须保留一个空格间距
> 类中的方法定义时,括号 `)` 也须与花括号 `{` 保留一个空格间距
```js
// 不好
class Foo{
constructor(){
// constructor
}
sayHi() {
// 仅保留一个空格间距
}
}
// 好
class Foo {
constructor() {
// constructor
}
sayHi() {
// 仅保留一个空格间距
}
}
```
- 6.2 定义类时,方法的顺序如下:
- `constructor`
- public `get/set` 公用访问器,`set`只能传一个参数
- public methods 公用方法,以函数命名区分,不带下划线
- private `get/set` 私有访问器,私有相关命名应加上下划线`_`为前缀
- private methods 私有方法
```js
class SomeClass {
constructor() {
// constructor
}
get aval() {
// public getter
}
set aval(val) {
// public setter
}
doSth() {
// 公用方法
}
get _aval() {
// private getter
}
set _aval() {
// private setter
}
_doSth() {
// 私有方法
}
}
```
- 6.3 如果不是class类,不使用`new`
```js
// 不好
function Foo() {
}
const foo = new Foo();
// 好
class Foo {
}
const foo = new Foo();
```
- 6.4 使用真正意思上的类Class写法,不使用`prototype`进行模拟扩展
> Class更加简洁,易维护
```js
// 不好
function Dog(names = []) {
this._names = [...names];
}
Dog.prototype.bark = function() {
const currName = this._names[0];
alert(`one one ${currName}`);
}
// 好
class Dog {
constructor(names = []) {
this._name = [...names];
}
bark() {
const currName = this._names[0];
alert(`one one ${currName}`);
}
}
```
- 6.5 class应先定义后使用
> class不存在hoist问题,应先定义class再实例化
> 使用继承时,应先定义父类再定义子类
```js
// 不好
let foo = new Foo();
class SubFoo extends Foo {
}
class Foo {
}
// 好
class Foo {
}
let foo = new Foo();
class SubFoo extends Foo {
}
```
- 6.6 `this`的注意事项
> 子类使用`super`关键字时,`this`应在调用`super`之后才能使用
> 可在方法中`return this`来实现链式调用写法
```js
class Foo {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
// 不好
class SubFoo extends Foo {
constructor(x, y, z) {
this.z = z; // 引用错误
super(x, y);
}
}
// 好
class SubFoo extends Foo {
constructor(x, y, z) {
super(x, y);
this.z = z; // this 放在 super 后调用
}
setHeight(height) {
this.height = height;
return this;
}
}
```
#### 模块
- 7.1 使用`import / export`来做模块加载导出,不使用非标准模块写法
> 跟着标准走的人,运气总不会太差
```js
// 不好
const colors = require('./colors');
module.exports = color.lightRed;
// 好
import { lightRed } from './colors';
export default lightRed;
```
- 7.1.1 `import / export` 后面采用花括号`{ }`引入模块的写法时,须在花括号内左右各保留一个空格
```js
// 不好
import {lightRed} from './colors';
import { lightRed} from './colors';
// 好
import { lightRed } from './colors';
```
- 7.2 应确保每个module有且只有一个默认导出模块
> 方便调用方使用
```js
// 不好
const lightRed = '#F07';
export lightRed;
// 好
const lightRed = '#F07';
export default lightRed;
```
- 7.3 `import` 不使用统配符 `* ` 进行整体导入
> 确保模块与模块之间的关系比较清晰
```js
// 不好
import * as colors from './colors';
// 好
import colors from './colors';
```
- 7.4 不要将`import`与`export`混合在一行
> 分开导入与导出,让结构更清晰,可读性更强
```js
// 不好
export { lightRed as default } from './colors';
// 好
import { lightRed } from './colors';
export default lightRed;
```
- 7.5 多变量要导出时应采用对象解构形式
> `export`置于底部,使欲导出变量更加清晰
```js
// 不好
export const lightRed = '#F07';
export const black = '#000';
export const white = '#FFF';
// 好
const lightRed = '#F07';
const black = '#000';
const white = '#FFF';
export default { lightRed, black, white };
```
#### Copyright
Copyright (c) 2015 [广发证券IT](http://it.gf.com.cn)