├── README.md └── es6-coding-style-en.md /README.md: -------------------------------------------------------------------------------- 1 | # ECMAScript6 编码规范--广发证券前端团队 2 | 3 | > 本规范是基于JavaScript规范拟定的,只针对ES6相关内容进行约定 4 | 5 | > 如变量命名,是否加分号等约定的请参考JavaScript规范 6 | 7 | > 应注意目前的代码转换工具(如Babel,traceur)不够完善,有些特性须谨慎使用 8 | 9 | ### [ES6 Coding Style English Version](https://github.com/gf-web/es6-coding-style/edit/master/es6-coding-style-en.md) 10 | 11 | ## 规范内容 12 | 13 | 1. [声明 Declarations](#声明) 14 | 2. [字符串 Strings](#字符串) 15 | 3. [解构 Destructuring](#解构) 16 | 4. [数组 Arrays](#数组) 17 | 5. [函数 Functions](#函数) 18 | 6. [类 Classes](#类) 19 | 7. [模块 Modules](#模块) 20 | 21 | ### 声明 22 | - 1.1 变量 23 | 24 | > 对于只在当前作用域下有效的变量,应使用`let`来代替`var` 25 | 26 | > 对于全局变量声明,采用`var`,但应避免声明过多全局变量污染环境 27 | 28 | ```js 29 | // 不好 30 | const variables; 31 | const globalObj = null; // 不是定义一个常量 32 | let globalObj = null; 33 | 34 | for (var i=0; i<5; i++) { 35 | console.log(i); 36 | } 37 | console.log(i); 38 | 39 | 40 | // 好 41 | let variables; 42 | var globalObj = null; 43 | 44 | for (let i=0; i<5; i++) { 45 | console.log(i); 46 | } 47 | console.log(i); 48 | ``` 49 | 50 | - 1.2 常量 51 | 52 | > 对于常量应使用`const`进行声明,命名应遵循字母全大写的通俗约定 53 | 54 | > 对于使用 immutable 数据应用`const`进行声明 55 | 56 | > 注意: `const`与`let`只在声明所在的块级作用域内有效 57 | 58 | ```js 59 | // 不好 60 | const someNum = 123; 61 | const AnotherStr = '不变的字符串'; 62 | let SOME_ARR = ['不','变','数','组']; 63 | var ANOTHER_OBJ = { 64 | '不变对象': true 65 | }; 66 | 67 | 68 | // 好 69 | const SOME_NUM = 123; 70 | const ANOTHER_STR = '不变的字符串'; 71 | const SOME_ARR = ['不','变','数','组']; 72 | const ANOTHER_OBJ = { 73 | '不变对象': true 74 | }; 75 | 76 | ``` 77 | 78 | #### 字符串 79 | 80 | - 2.1 模板字符串 81 | 82 | > 对于多行字符串,拼接变量的情况适用模板字符串,以反引号( ` )标示 83 | 84 | > 可读性更强,代码更易编写 85 | 86 | ```js 87 | // 不好 88 | const multiStr = '多行字符串换行表示,\n 这是换行了。'; 89 | function sayHi(name) { 90 | return 'How are you, ' + name + '?'; 91 | } 92 | 93 | 94 | // 好 95 | const multiStr = `多行字符串换行表示, 96 | 这是换行了。`; 97 | function sayHi(name) { 98 | return `How are you, ${name}?`; 99 | } 100 | ``` 101 | 102 | #### 解构 103 | 104 | - 3.1 嵌套结构的对象层数不能超过3层 105 | 106 | ```js 107 | // 不好 108 | let obj = { 109 | 'one': [ 110 | { 'newTwo': [ 111 | { 'three': [ 112 | 'four': '太多层了,头晕晕' 113 | ] 114 | } 115 | ] 116 | ] 117 | }; 118 | 119 | 120 | // 好 121 | let obj = { 122 | 'one': [ 123 | 'two', 124 | {'twoObj': '结构清晰' } 125 | ] 126 | }; 127 | 128 | ``` 129 | 130 | - 3.2 解构语句中统一不使用圆括号 131 | 132 | ```js 133 | // 不好 134 | [(a)] = [11]; // a未定义 135 | let { a: (b) } = {}; // 解析出错 136 | 137 | // 好 138 | let [a, b] = [11, 22]; 139 | ``` 140 | 141 | - 3.3 对象解构 142 | 143 | > 对象解构 元素与顺序无关 144 | 145 | > 对象指定默认值时仅对恒等于undefined ( !== null ) 的情况生效 146 | 147 | - 3.3.1 若函数形参为对象时,使用对象解构赋值 148 | 149 | ```js 150 | // 不好 151 | function someFun(opt) { 152 | let opt1 = opt.opt1; 153 | let opt2 = opt.opt2; 154 | console.log(op1); 155 | } 156 | 157 | 158 | // 好 159 | function someFun(opt){ 160 | let {opt1, opt2} = opt; 161 | console.log( `$(opt1) 加上 $(opt2)` ); 162 | } 163 | 164 | function someFun( {opt1, opt2} ){ 165 | console.log(opt1); 166 | } 167 | ``` 168 | 169 | - 3.3.2 若函数有多个返回值时,使用对象解构,不使用数组解构,避免添加顺序的问题 170 | 171 | ```js 172 | // 不好 173 | 174 | function anotherFun(){ 175 | const one = 1, two = 2, three = 3; 176 | return [one, two, three]; 177 | } 178 | 179 | const [one, three, two] = anotherFun(); // 顺序乱了 180 | 181 | // 好 182 | function anotherFun(){ 183 | const one = 1, two = 2, three = 3; 184 | return { one, two, three }; 185 | } 186 | 187 | const { one, three, two } = anotherFun(); // 不用管顺序 188 | ``` 189 | 190 | - 3.3.3 已声明的变量不能用于解构赋值(语法错误) 191 | 192 | ```js 193 | // 语法错误 194 | let a; 195 | {a} = {a: 123}; 196 | 197 | ``` 198 | 199 | - 3.4 数组解构 200 | 201 | > 数组元素与顺序相关 202 | 203 | -3.4.1 交换变量的值 204 | 205 | ```js 206 | let x = 1; 207 | let y = 2; 208 | 209 | // 不好 210 | let temp; 211 | temp = x; 212 | x = y; 213 | y = temp; 214 | 215 | 216 | // 好 217 | [x, y] = [y, x]; // 交换变量 218 | ``` 219 | 220 | - 3.4.2 将数组成员赋值给变量时,使用数组解构 221 | 222 | ```js 223 | const arr = [1,2,3,4,5]; 224 | 225 | // 不好 226 | const one = arr[0]; 227 | const two = arr[1]; 228 | 229 | 230 | // 好 231 | const [one, two] = arr; 232 | ``` 233 | 234 | #### 数组 235 | 236 | - 4.1 将类数组(array-like)对象与可遍历对象(如`Set`, `Map`)转为真正数组 237 | 238 | > 采用`Array.from`进行转换 239 | 240 | ```js 241 | // 不好 242 | function foo(){ 243 | let args = Array.prototype.slice.call(arguments); 244 | } 245 | 246 | 247 | // 好 248 | function foo(){ 249 | let args = Array.from(arguments); 250 | } 251 | 252 | ``` 253 | - 4.2 数组去重 254 | 255 | > 结合Set结构与`Array.from` 256 | 257 | ```js 258 | // 不好 259 | // 使用indexOf,HashTable等形式,不够简洁清晰 260 | 261 | 262 | // 好 263 | function deduplication(arr){ 264 | return Array.from(new Set(arr)); 265 | } 266 | 267 | ``` 268 | - 4.3 数组拷贝 269 | 270 | > 采用数组扩展`...`形式 271 | 272 | ```js 273 | const items = [1,2,3]; 274 | 275 | // 不好 276 | const len = items.length; 277 | let copyTemp = []; 278 | for (let i=0; i 采用`Array.of`进行转换 289 | 290 | ```js 291 | // 不好 292 | let arr1 = new Array(2); // [undefined x 2] 293 | let arr2 = new Array(1,2,3); // [1, 2, 3] 294 | 295 | 296 | // 好 297 | let arr1 = Array.of(2); // [2] 298 | let arr2 = Array.of(1,2,3); // [1, 2, 3] 299 | ``` 300 | 301 | #### 函数 302 | 303 | - 5.1 当要用函数表达式或匿名函数时,使用箭头函数(Arrow Functions) 304 | 305 | > 箭头函数更加简洁,并且绑定了this 306 | 307 | ```js 308 | // 不好 309 | const foo = function(x){ 310 | console.log('存在函数提升问题'); 311 | console.log(foo.name); // 返回'' ,函数表达式不可命名,函数声明可以 312 | }; 313 | 314 | [1, 2, 3].forEach(function(x){ 315 | return x + 1; 316 | }); 317 | 318 | 319 | // 好 320 | const foo = x => { 321 | console.log('不存在函数提升问题'); 322 | console.log(foo.name); // 返回'foo' 323 | }; 324 | 325 | [1, 2, 3].forEach( x => { 326 | return x + 1; 327 | }); 328 | ``` 329 | 330 | - 5.1.1 箭头函数书写约定 331 | 332 | > 函数体只有单行语句时,允许写在同一行并去除花括号 333 | 334 | > 当函数只有一个参数时,允许去除参数外层的括号 335 | 336 | ```js 337 | // 好 338 | const foo = x => x + x; // 注意此处会默认return x + x,有花括号语句块时不会return 339 | 340 | [1, 2, 3].map(x => x * x); 341 | 342 | ``` 343 | - 5.1.2 用箭头函数返回一个对象,应用括号包裹 344 | 345 | ```js 346 | // 不好 347 | let test = x => {x:x}; // 花括号会变成语句块,不表示对象 348 | 349 | 350 | // 好 351 | let test = x => ({x:x}); // 使用括号可正确return {x:x} 352 | ``` 353 | 354 | - 5.2 立即调用函数 IIFE 355 | 356 | > 使用箭头函数 357 | 358 | ```js 359 | // 不好 360 | (function(){ 361 | console.log('哈'); 362 | })(); 363 | 364 | 365 | // 好 366 | (() => { 367 | console.log('哈'); 368 | })(); 369 | 370 | ``` 371 | 372 | - 5.3 不使用 `arguments`, 采用rest语法`...`代替 373 | 374 | > rest参数是真正的数组,不需要再转换 375 | 376 | > 注意:箭头函数中不能使用`arguments`对象 377 | 378 | ```js 379 | // 不好 380 | function foo(){ 381 | let args = Array.prototype.slice.call(arguments); 382 | return args.join(''); 383 | } 384 | 385 | 386 | // 好 387 | function foo(...args) { 388 | return args.join(''); 389 | } 390 | 391 | ``` 392 | 393 | - 5.4 函数参数指定默认值 394 | 395 | > 采用函数默认参数赋值语法 396 | 397 | ```js 398 | // 不好 399 | function foo(opts) { 400 | opts = opts || {};// 此处有将0,''等假值转换掉为默认值的副作用 401 | } 402 | 403 | 404 | // 好 405 | function foo( opts = {}) { 406 | console.log('更加简洁,安全'); 407 | } 408 | ``` 409 | 410 | - 5.5 对象中的函数方法使用缩写形式 411 | 412 | > 更加简洁 413 | 414 | ```js 415 | // 不好 416 | const shopObj = { 417 | des: '对象模块写法', 418 | foo: function(){ 419 | console.log('对象中的方法'); 420 | } 421 | }; 422 | 423 | // 好 424 | const shopObj = { 425 | des: '对象模块写法', 426 | foo(){ 427 | console.log('对象中的方法'); 428 | } 429 | }; 430 | ``` 431 | 432 | 433 | #### 类 434 | 435 | - 6.1 类名应使用帕斯卡写法(PascalCased) 436 | 437 | ```js 438 | class SomeClass{ 439 | } 440 | ``` 441 | 442 | - 6.2 定义类时,方法的顺序如下: 443 | 444 | - `constructor` 445 | 446 | - public `get/set` 公用访问器,`set`只能传一个参数 447 | 448 | - public methods 公用方法,以函数命名区分,不带下划线 449 | 450 | - private `get/set` 私有访问器,私有相关命名应加上下划线`_`为前缀 451 | 452 | - provate methods 私有方法 453 | 454 | ```js 455 | class SomeClass { 456 | constructor() { 457 | // constructor 458 | } 459 | 460 | get aval() { 461 | // public getter 462 | } 463 | 464 | set aval(val) { 465 | // public setter 466 | } 467 | 468 | doSth() { 469 | // 公用方法 470 | } 471 | 472 | get _aval() { 473 | // private getter 474 | } 475 | 476 | set _aval() { 477 | // private setter 478 | } 479 | 480 | _doSth() { 481 | // 私有方法 482 | } 483 | } 484 | 485 | ``` 486 | 487 | - 6.3 如果不是class类,不使用`new` 488 | 489 | ```js 490 | // 不好 491 | function Foo() { 492 | } 493 | const foo = new Foo(); 494 | 495 | 496 | // 好 497 | class Foo() { 498 | } 499 | const foo = new Foo(); 500 | ``` 501 | 502 | 503 | - 6.4 使用真正意思上的类Class写法,不使用`prototype`进行模拟扩展 504 | 505 | > Class更加简洁,易维护 506 | 507 | ```js 508 | // 不好 509 | function Dog(names = []) { 510 | this._names = [...names]; 511 | } 512 | Dog.prototype.bark = function(){ 513 | const currName = this._names[0]; 514 | alert(`one one ${currName}`); 515 | } 516 | 517 | // 好 518 | class Dog { 519 | constructor(names = []){ 520 | this._name = [...names]; 521 | } 522 | bark() { 523 | const currName = this._names[0]; 524 | alert(`one one ${currName}`); 525 | } 526 | } 527 | ``` 528 | 529 | - 6.5 class应先定义后使用 530 | 531 | > 虽然规范里class不存在hoist问题,但转换工具如babel,只是转换为函数表达式,此处仍有hoist 532 | 533 | > 使用继承时,应先定义父类再定义子类 534 | 535 | ```js 536 | // 不好 537 | let foo = new Foo(); 538 | class Foo { } 539 | 540 | 541 | // 好 542 | class Foo { } 543 | let foo = new Foo(); 544 | 545 | class SubFoo extends Foo { 546 | 547 | } 548 | ``` 549 | 550 | - 6.6 `this`的注意事项 551 | 552 | > 子类使用`super`关键字时,`this`应在调用`super`之后才能使用 553 | 554 | > 可在方法中`return this`来实现链式调用写法 555 | 556 | ```js 557 | class Foo { 558 | constructor(x, y) { 559 | this.x = x; 560 | this.y = y; 561 | } 562 | } 563 | 564 | // 不好 565 | class SubFoo extends Foo { 566 | constructor(x, y, z) { 567 | this.z = z; // 引用错误 568 | super(x, y); 569 | } 570 | } 571 | 572 | 573 | // 好 574 | class SubFoo extends Foo { 575 | constructor(x, y, z) { 576 | super(x, y); 577 | this.z = z; // this 放在 super 后调用 578 | } 579 | setHeight(height) { 580 | this.height = height; 581 | return this; 582 | } 583 | } 584 | ``` 585 | 586 | 587 | #### 模块 588 | 589 | - 7.1 使用`import / export`来做模块加载导出,不使用非标准模块写法 590 | 591 | > 跟着标准走的人,运气总不会太差 592 | 593 | ```js 594 | // 不好 595 | const colors = require('./colors'); 596 | module.exports = color.lightRed; 597 | 598 | 599 | // 好 600 | import { lightRed } from './colors'; 601 | export default lightRed; 602 | 603 | ``` 604 | 605 | - 7.2 应确保每个module有且只有一个默认导出模块 606 | 607 | > 方便调用方使用 608 | 609 | ```js 610 | // 不好 611 | const lightRed = '#F07'; 612 | 613 | export lightRed; 614 | 615 | 616 | // 好 617 | const lightRed = '#F07'; 618 | 619 | export default lightRed; 620 | ``` 621 | 622 | - 7.3 `import` 不使用统配符 `* ` 进行整体导入 623 | 624 | > 确保模块与模块之间的关系比较清晰 625 | 626 | ```js 627 | // 不好 628 | import * as colors from './colors'; 629 | 630 | // 好 631 | import colors from './colors'; 632 | 633 | ``` 634 | 635 | - 7.4 不要将`import`与`export`混合在一行 636 | 637 | > 分开导入与导出,让结构更清晰,可读性更强 638 | 639 | ```js 640 | // 不好 641 | export { lightRed as default } from './colors'; 642 | 643 | // 好 644 | import { lightRed } from './colors'; 645 | export default lightRed; 646 | ``` 647 | 648 | - 7.5 多变量要导出时应采用对象解构形式 649 | 650 | > `export`置于底部,使欲导出变量更加清晰 651 | 652 | ```js 653 | // 不好 654 | export const lightRed = '#F07'; 655 | export const black = '#000'; 656 | export const white = '#FFF'; 657 | 658 | // 好 659 | const lightRed = '#F07'; 660 | const black = '#000'; 661 | const white = '#FFF'; 662 | 663 | export default { lightRed, black, white }; 664 | ``` 665 | 666 | -------------------------------------------------------------------------------- /es6-coding-style-en.md: -------------------------------------------------------------------------------- 1 | ### Coming soon! 2 | --------------------------------------------------------------------------------