ES6 实践规范
栏目: JavaScript · 发布时间: 7年前
内容简介:ES6 实践规范
前言:团队基于ES6和Eslint规则规定代码规范,本文的目的是梳理和总结团队现在实行的规范。
作者:郑灵华,点餐秒付终端团队成员
目录
一、Eslint检测ES6规范配置
- 编码格式规范
- 声明唯一性
- 初始化定义规范
- 代码编写注意事项
- 派生类相关
二、Airbnb规范节选
- 箭头函数
- 构造器
- 迭代遍历
- 属性定义
- 解构
- 函数
三、参考资料
一、Eslint检测ES6规范配置
1. 编码格式规范
a.规定箭头函数强制大括号
b.规定箭头函数参数是否要使用括号
c.规定箭头函数的箭头前后的空格规范
号周围的空格
e.规定rest参数和扩展运算符与他们的参数之间的空格
f.禁止模板字面量中的花括号出现括号
g.强制在 yield
表达式中 * 后面使用空格a.规定箭头函数强制大括号
//Eslint文件配置项 'arrow-body-style': ['error', 'as-needed', { requireReturnForObjectLiteral: false, }]
参数 | 参数说明 | 备注 |
---|---|---|
as-needed | 当大括号是可省略的,强制不使用 | |
requireReturnForObjectLiteral | 不需要显式返回对象字面量 | 必须与as-needed 搭配使用 |
//项目中正确使用事例 //可以省略大括号 let foo = () => 0; //不用显式返回对象字面量 let foo = () => ({ bar: 0 }); //错误对比: let foo = () => { return ({bar: 0 }); };
b.规定箭头函数参数是否要使用括号
//Eslint文件配置项 'arrow-parens': ['error', 'as-needed', { requireForBlockBody: true, }]
参数 | 参数说明 | 备注 |
---|---|---|
as-needed | 当只有一个参数时允许省略圆括号 | |
requireForBlockBody | 当函数体在一个指令块中,参数必须用圆括号包含 | 作为as-needed补充。以函数体是否被 { } 包括快速判断 |
//项目实践正确例子 // 只有一个参数允许省略 a.map(x => { return x * x; }); // requireForBlockBody 参数作为补充,上述代码修改成 a.map((x) => { return x * x; });
c.箭头函数的箭头前后的空格规范
'arrow-spacing': ['error', { before: true, after: true }]
参数 | 参数说明 | 备注 |
---|---|---|
before | 箭头前面有空格 | |
after | 箭头后面有空格 |
//项目应用 a => a;
d.generator 函数中 * 号周围的空格
'generator-star-spacing': ['error', { before: false, after: true }]
参数 | 参数说明 | 备注 |
---|---|---|
before | *前面没有空格 | |
after | *后面有空格 |
//项目正确使用示例 function* generator() {}
e.不允许rest参数和扩展运算符与他们的参数之间有空格
'rest-spread-spacing': ['error', 'never']
参数 | 参数说明 | 备注 |
---|---|---|
never | 符号和参数之间不能有空格 |
//rest参数 let [a, b, ...arr] = [1, 2, 3, 4, 5] //扩展运算符 function fn(){} fn(...args)
f.禁止模板字面量中的花括号出现括号
'template-curly-spacing': 'error'
//花括号里面没有括号 `hello, ${people.name}!`
g.强制在 yield 表达式中 后面使用空格
'yield-star-spacing': ['error', 'after']
function* generator() { yield* other(); }
2. 声明唯一性
a.不能修改类声明的变量
b.禁止修改const声明的变量
c.不允许类成员里有重复的名称
d.不要重复引入一个模块
e.禁止在import,export,解构赋值中重命名和原有名字相同
a.不能修改类声明的变量
'no-class-assign': 'error'
// 简而言之,如果以class Name{}形object-shorthand式出现,那么Name不能做任何更改和赋值 // 下面例子是正确的。因为A至始至终只是变量 let A = class { b() { A = 0; console.log(A); } } console.log(A); //class let Foo = new A(); Foo.b(); //0 console.log(A); //0
b.禁止修改const声明的变量
'no-const-assign': 'error'
c.不允许类成员里有重复的名称
'no-dupe-class-members': 'error'
d.不要重复引入一个模块
'no-duplicate-imports': 'off'
//同一个模块引入两个变量应该写在一个大括号里面 import { merge, find } from 'module';
e.禁止在import,export,解构赋值中重命名和原有名字相同
'no-useless-rename': ['error', { ignoreDestructuring: false, ignoreImport: false, ignoreExport: false, }]
//形如{ foo as foo }和{ bar: bar }并没有起到重命名的作用,所以应该禁止这种冗余书写 import { foo as bar } from "baz"; export { foo as bar } from "foo"; let { [foo]: foo } = bar;
3. 初始化定义规范
a.Symbol类型不能用new关键字
b.Symbol定义的时候增加描述语言,便于debug
c.generator函数里面一定要有yield
d.使用 let 或 const 而不是 var
e.禁止在字面量声明无用的计算属性
f.若变量不会再次赋值,使用const声明
a.Symbol类型不能用new关键字
'no-new-symbol': 'error'
//symbol应该以函数形式调用 var foo = Symbol('foo');
b.Symbol定义的时候增加描述语言,便于debug
'symbol-description': 'error'
let foo = Symbol("some description")
c.generator函数里面一定要有yield
'require-yield': 'error'
d.使用 let 或 const 而不是 var
'no-var': 'error'
e.禁止在字面量声明无用的计算属性
'no-useless-computed-key': 'error'
//无用的["a"]计算属性 var foo = {['0+1,234']: "b"}; //改写成 var foo = { '0+1,234': 0 };
f.若变量不会再次赋值,使用const声明
'prefer-const': ['error', { destructuring: 'any', ignoreReadBeforeAssign: true, }]
参数 | 参数说明 | 备注 |
---|---|---|
destructuring | 解构赋值时,所有变量的类型都应该保持一致 | |
ignoreReadBeforeAssign | 忽略声明和第一次赋值之间的变量 | 也就是不能先定义后赋值 |
//解构赋值时,值要么都是const要么都是let // a0是确定的,b没有被赋值 const {a: a0, b} = obj; const a = a0 + 1; // a,b都是变量,所以解构赋值定义用let let {a, b} = obj; a = a + 1; b = b + 1; //错误例子,在ignoreReadBeforeAssign=true时,timer的声明和赋值之间的initialize()函数声明会被省略。 //从而会在setInterval处报错函数undefined let timer; function initialize() { if (foo()) { clearInterval(timer); } } timer = setInterval(initialize, 100); //正确例子,只要声明就要赋值! const timer = setInterval(initialize, 100); function initialize() { if (foo()) { clearInterval(timer); } }
4.代码编写注意事项
a. 避免箭头函数和比较式混淆
b. 使用模板字面量而不是字符串拼接
c. 使用扩展运算符(...)而非.apply()调用可变参数
d. 用rest参数(...变量名)替换arguments
e. 不允许使用parseInt()转化2,8,16进制
f. 要求使用箭头函数进行回调
g. 对象字面量语法简写
a.避免箭头函数和比较式混淆
'no-confusing-arrow': ['error', { allowParens: true, }]
参数 | 参数说明 | 备注 |
---|---|---|
allowParens | 放宽标准,允许箭头函数使用括号 | 不强制必须用return返回 |
//如果是严格模式,会发现即使用圆括号包含,也要用return区分箭头函数和三元运算比较 var x = a => { return 1 ? 2 : 3; }; var x = (a) => { return 1 ? 2 : 3; }; //如果allowParens=true,则放宽标准 var x = a => (1 ? 2 : 3); var x = (a) => (1 ? 2 : 3);
b.使用模板字面量而不是字符串拼接
'prefer-template': 'error'
let str = `Hello, ${name}!`
c.使用扩展运算符(...)而非.apply()调用可变参数
'prefer-spread': 'error'
//求出一个数组最大元素 Math.max.apply(null, [14, 3, 77]) //等效于 Math.max(...[14, 3, 77]) //等同 Math.max(14, 3, 77)
d.用rest参数(...变量名)替换arguments
'prefer-rest-params': 'error'
//rest运算符可以提供一个真正的数组,能显式表示参数 //而arguments是一个对象,操作中要通过call等手段调用数组方法 function foo(...args) { console.log(args); }
e. 不允许使用parseInt()转化2,8,16进制
'prefer-numeric-literals': 'error'
//只针对2,8,16进制使用 //数字转化成其他进制或者是变量转化还是用parseInt 0b111110111 === 503; 0o767 === 503; 0x1F7 === 503; parseInt(1, 3); parseInt(foo, 2);
f. 要求使用箭头函数进行回调
'prefer-arrow-callback': ['error', { allowNamedFunctions: false, allowUnboundThis: true, }]
参数 | 参数说明 | 备注 |
---|---|---|
allowNamedFunctions | 如果回调函数里面是命名函数则报错 | |
allowUnboundThis | 不使用bind()指定this,规则会动态标记this的使用 |
//直接使用this,而不是bind(this) //回调函数里是匿名函数 foo(function() { return this.a; });
g.对象字面量语法简写
'object-shorthand': ['error', 'always', { ignoreConstructors: false, avoidQuotes: true, }]
参数 | 参数说明 | 备注 |
---|---|---|
always | 能简写就简写 | |
ignoreConstructors | 构造函数不能省略 | 必须指定第一个参数 |
avoidQuotes | 对象键是字符串时,用长格式 | 必须指定第一个参数 |
// 因为foo对象两个键都是string,所以后面不能省略 var foo = { "bar-baz": function() {}, "qux": qux }
5.派生类相关
a. 构造函数必须调用 super
b. 禁止不必要的构造函数
c. 派生类函数构造器禁止在super()之前使用this
a. 构造函数必须调用 super
'constructor-super': 'error'
//派生类中构造函数必须调用,非派生类的构造函数不能调用super() class A { constructor() { } } class A extends B { constructor() { super(); } }
b. 禁止不必要的构造函数
'no-useless-constructor': 'error'
//简单讲便是构造器里面一定要有执行的逻辑代码 class A { constructor () { doSomething(); } } //如果没有特别的逻辑,则类返回空即可 class A { }
c. 派生类函数构造器禁止在super()之前使用this
'no-this-before-super': 'error
//否则会返回引用错误(reference error) class A extends B { constructor() { super(); this.a = 0; // OK, this is after `super()`. } }
二、Airbnb规范节选
1. 箭头函数
- 当函数特别简单,并且只有一个参数,可省略花括号、圆括号、return
- 提高链式调用可读性,不断传递this
- 但是结果需要回传一个对象时,不能省略return
2. 构造器
- 用class替代prototype
//用class更为简洁 class Foo { constructor(){} getVal(){} } //等价于 Foo.prototype = { getVal(){} }
- 用extends实现继承,不直接操作prototype
- class能实现模块开发,并且能通过返回this实现链式调用
- 类的数据类型就是函数,类本身就指向构造函数
class Foo {} typeof Foo; // Function Foo === Foo.prototype.constructor; //true
3. 迭代遍历
- ES6提供的遍历器Iterator,适合于部署了Symbol.iterator属性的数据结构,可以用for...of遍历成员
- for...in遍历object所有可枚举对象,包含当前对象和原型上
- for...of遍历collection对象,并不适用所有object,视乎其是否有[Symbol.iterator]属性。且只遍历当前对象
- Airbnb推荐使用高阶函数例如 map() 和 reduce() 替代 for-of,便于处理函数回调
4. 属性定义
- 如果对象具有动态属性名,在一开始使用可计算的属性名称,保证所有属性定义在一起
const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, }
5. 解构
- 推荐使用解构赋值,减少临时变量的引入
- 需要回传多个值时,使用对象解构,而不是数组解构,方便调用时可以忽略顺序
// 数组解构=>调用时回调数据的顺序是一一对应的 function processInput(input) { // then a miracle occurs return [left, right, top, bottom]; } const [left, __, top] = processInput(input); // 对象解构=>不考虑顺序,只要保证变量必须与属性同名 function processInput(input) { // then a miracle occurs return { left, right, top, bottom }; } const { left, right } = processInput(input);
- 对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: baz } = { foo: "aaa", bar: "bbb" }; baz; // "aaa" foo; // error: foo is not defined
6. 函数
- 使用函数声明代替函数表达式,便于在调用栈识别,避免整个函数被提升。同时,箭头函数可以取代函数表达式
- 不要把参数命名为 arguments。这将取代原来函数作用域内的 arguments 对象
- 不要使用 arguments。用 rest 语法 ... 替代
- 推荐: 函数参数应该指定默认值
//bad code,如果是Boolean,传进去甚至会改变opts的类型 function handleThings(opts) { opts = opts || {}; } //Airbnb 推荐写法,初始化参数 function handleThings(opts = {}) {}
三、参考资料
以上所述就是小编给大家介绍的《ES6 实践规范》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- vue项目实践004~~~一篮子的实践技巧
- HBase实践 | 阿里云HBase数据安全实践
- Spark 实践:物化视图在 SparkSQL 中的实践
- Spark实践|物化视图在 SparkSQL 中的实践
- HBase实践 | 数据人看Feed流-架构实践
- Kafka从上手到实践-实践真知:搭建Zookeeper集群
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。