├── .gitattributes ├── .gitignore └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # EcmaScript6 全规范(含node) 2 | 3 | * 一、类型规范 4 | * 二、字符串模板 5 | * 三、数组类型 6 | * 四、解构类型 7 | * 五、函数 8 | * 六、arrow箭头函数 9 | * 七、对象 10 | * 八、类 11 | * 九、模块 12 | * 十、Iterators 和 Generators 13 | * 十一、属性访问 14 | * 十二、map + set + weakmap + weakset 数据结构 15 | * 十三、promise、symbols、proxies 16 | * 十四、统一码 17 | * 十五、进制数支持 18 | * 十六、不建议使用reflect对象和tail calls尾调用 19 | 20 | 21 | ## 一、类型规范 22 | > 对于常量或不修改的变量声明使用const,对于只在当前作用域下有效的变量,应使用let,全局变量使用var。将所有 const 变量放在一起,然后将所有 let 变量放在一起 23 | 24 | ```javascript 25 | 26 | const foo = 1; 27 | 28 | let foo1 = 2; 29 | let bar = foo; 30 | bar = 9; 31 | foo1 = 3; 32 | 33 | console.log(foo, bar); // => 1, 9 34 | console.log(foo, bar, str); // => 1, 9,'ouven' 35 | 36 | ``` 37 | 38 | > const和let使用时注意,let 和 const 都是块作用域的 39 | 40 | ```javascript 41 | 42 | // const and let only exist in the blocks they are defined in. 43 | { 44 | let a = 1; 45 | const b = 1; 46 | } 47 | console.log(a); // ReferenceError 48 | console.log(b); // ReferenceError 49 | 50 | ``` 51 | 52 | ## 二、字符串 53 | > 使用单引号 ' 54 | 55 | ```javascript 56 | 57 | // bad 58 | var name = "Bob Parr"; 59 | 60 | // good 61 | var name = 'Bob Parr'; 62 | 63 | // bad 64 | var fullName = "Bob " + this.lastName; 65 | 66 | // good 67 | var fullName = 'Bob ' + this.lastName; 68 | 69 | ``` 70 | 71 | 超过80个字符的字符串应该使用字符串连接换行 72 | 注:如果过度使用长字符串连接可能会对性能有影响。jsPerf & Discussion 73 | 74 | ```javascript 75 | 76 | // bad 77 | var 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.'; 78 | 79 | // bad 80 | var errorMessage = 'This is a super long error that \ 81 | was thrown because of Batman. \ 82 | When you stop to think about \ 83 | how Batman had anything to do \ 84 | with this, you would get nowhere \ 85 | fast.'; 86 | 87 | 88 | // good 89 | var errorMessage = 'This is a super long error that ' + 90 | 'was thrown because of Batman.' + 91 | 'When you stop to think about ' + 92 | 'how Batman had anything to do ' + 93 | 'with this, you would get nowhere ' + 94 | 'fast.'; 95 | 96 | ``` 97 | 98 | > 编程构建字符串时,使用字符串模板而不是字符串连接 99 | 100 | 模板给你一个可读的字符串,简洁的语法与适当的换行和字符串插值特性。 101 | 102 | ```javascript 103 | 104 | // bad 105 | function sayHi(name) { 106 | return 'How are you, ' + name + '?'; 107 | } 108 | 109 | // bad 110 | function sayHi(name) { 111 | return ['How are you, ', name, '?'].join(); 112 | } 113 | 114 | // good 115 | function sayHi(name) { 116 | return `How are you, ${name}?`; 117 | } 118 | ``` 119 | 120 | ## 三、数组类型 121 | > 使用字面量语法创建数组 122 | 123 | ```javascript 124 | // bad 125 | const items = new Array(); 126 | 127 | // good 128 | const items = []; 129 | ``` 130 | > 如果你不知道数组的长度,使用 push 131 | 132 | ```javascript 133 | const someStack = []; 134 | 135 | // bad 136 | someStack[someStack.length] = 'abracadabra'; 137 | 138 | // good 139 | someStack.push('abracadabra'); 140 | ``` 141 | > 使用 ... 来拷贝数组,不要使用 Array.from、Array.of等数组的新的内置API,Array新api用于适合的场景 142 | 143 | ```javascript 144 | // bad 145 | const len = items.length; 146 | const itemsCopy = []; 147 | let i; 148 | 149 | for (i = 0; i < len; i++) { 150 | itemsCopy[i] = items[i]; 151 | } 152 | 153 | // good 154 | const itemsCopy = [...items]; 155 | 156 | // not good 157 | const foo = [1,2,3]; 158 | const nodes = Array.from(foo); 159 | ``` 160 | 161 | ## 四、解构 Destructuring 162 | 使用对象的多个属性时请建议使用对象的解构赋值,解构赋值避免了为这些属性创建临时变量或对象。即使转化成es5都是一样的 163 | 164 | > 嵌套结构的对象层数不能超过3层 165 | 166 | ```javascript 167 | // not good 168 | let obj = { 169 | 'one': [ 170 | { 171 | 'newTwo': [ 172 | { 173 | 'three': [ 174 | 'four': '太多层了,头晕晕' 175 | ] 176 | } 177 | ] 178 | } 179 | ] 180 | }; 181 | 182 | // good 183 | let obj = { 184 | 'one': [ 185 | 'two', 186 | { 187 | 'twoObj': '结构清晰' 188 | } 189 | ] 190 | }; 191 | ``` 192 | > 解构语句中统一不使用圆括号 193 | 194 | ```javascript 195 | // not good 196 | [(a)] = [11]; // a未定义 197 | let { a: (b) } = {}; // 解析出错 198 | 199 | 200 | // good 201 | let [a, b] = [11, 22]; 202 | ``` 203 | > 对象解构 204 | 205 | 对象解构元素与顺序无关 206 | 对象指定默认值时仅对恒等于undefined ( !== null ) 的情况生效 207 | 208 | > 若函数形参为对象时,使用对象解构赋值 209 | 210 | ```javascript 211 | // not good 212 | function someFun(opt) { 213 | let opt1 = opt.opt1; 214 | let opt2 = opt.opt2; 215 | console.log(op1); 216 | } 217 | 218 | 219 | // good 220 | function someFun(opt) { 221 | let { opt1, opt2 } = opt; 222 | console.log(`$(opt1) 加上 $(opt2)`); 223 | } 224 | 225 | function someFun({ opt1, opt2 }) { 226 | console.log(opt1); 227 | } 228 | ``` 229 | > 若函数有多个返回值时,使用对象解构,不使用数组解构,避免添加顺序的问题 230 | 231 | ```javascript 232 | // not good 233 | function anotherFun() { 234 | const one = 1, two = 2, three = 3; 235 | return [one, two, three]; 236 | } 237 | const [one, three, two] = anotherFun(); // 顺序乱了 238 | // one = 1, two = 3, three = 2 239 | 240 | 241 | // good 242 | function anotherFun() { 243 | const one = 1, two = 2, three = 3; 244 | return { one, two, three }; 245 | } 246 | const { one, three, two } = anotherFun(); // 不用管顺序 247 | // one = 1, two = 2, three = 3 248 | ``` 249 | > 已声明的变量不能用于解构赋值(语法错误) 250 | 251 | ```javascript 252 | // 语法错误 253 | let a; 254 | { a } = { b: 123}; 255 | ``` 256 | 257 | > 数组解构时数组元素与顺序相关 258 | 259 | 例如交换数组两个元素的值 260 | 261 | ```javascript 262 | let x = 1; 263 | let y = 2; 264 | 265 | // not good 266 | let temp; 267 | temp = x; 268 | x = y; 269 | y = temp; 270 | 271 | 272 | // good 273 | [x, y] = [y, x]; // 交换变量 274 | ``` 275 | > 将数组成员赋值给变量时,使用数组解构 276 | 277 | ```javascript 278 | const arr = [1, 2, 3, 4, 5]; 279 | 280 | // not good 281 | const one = arr[0]; 282 | const two = arr[1]; 283 | 284 | 285 | // good 286 | const [one, two] = arr; 287 | ``` 288 | 289 | > 函数有多个返回值时使用对象解构,而不是数组解构。 290 | 291 | 这样你就可以随时添加新的返回值或任意改变返回值的顺序,而不会导致调用失败。 292 | 293 | ```javascript 294 | 295 | function processInput(input) { 296 | // then a miracle occurs 297 | return [left, right, top, bottom]; 298 | } 299 | 300 | // the caller needs to think about the order of return data 301 | const [left, __, top] = processInput(input); 302 | 303 | // good 304 | function processInput(input) { 305 | // then a miracle occurs 306 | return { left, right, top, bottom }; 307 | } 308 | 309 | // the caller selects only the data they need 310 | const { left, right } = processInput(input); 311 | ``` 312 | 313 | ## 五、函数 314 | >使用函数声明而不是函数表达式 315 | 316 | 函数声明拥有函数名,在调用栈中更加容易识别。并且,函数声明会整体提升,而函数表达式只会提升变量本身。这条规则也可以这样描述,始终使用箭头函数来代替函数表达式。 317 | 318 | ```javascript 319 | // bad 320 | const foo = function () { 321 | }; 322 | 323 | // good 324 | function foo() { 325 | } 326 | ``` 327 | 绝对不要在一个非函数块(if,while,等等)里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同 328 | 注:ECMA-262 把 块 定义为一组语句,函数声明不是一个语句。阅读 ECMA-262 对这个问题的说明 329 | 330 | ```javascript 331 | // bad 332 | if (currentUser) { 333 | function test() { 334 | console.log('Nope.'); 335 | } 336 | } 337 | 338 | // good 339 | if (currentUser) { 340 | var test = function test() { 341 | console.log('Yup.'); 342 | }; 343 | } 344 | ``` 345 | > 绝对不要把参数命名为 arguments, 这将会覆盖函数作用域内传过来的 arguments 对象 346 | 347 | ```javascript 348 | // bad 349 | function nope(name, options, arguments) { 350 | // ...stuff... 351 | } 352 | 353 | // good 354 | function yup(name, options, args) { 355 | // ...stuff... 356 | } 357 | ``` 358 | > 永远不要使用 arguments,使用 ... 操作符来代替 359 | 360 | ... 操作符可以明确指定你需要哪些参数,并且得到的是一个真实的数组,而不是 arguments 这样的类数组对象。 361 | 362 | ```javascript 363 | // bad 364 | function concatenateAll() { 365 | const args = Array.prototype.slice.call(arguments); 366 | return args.join(''); 367 | } 368 | 369 | // good 370 | function concatenateAll(...args) { 371 | return args.join(''); 372 | } 373 | ``` 374 | > 使用函数参数默认值语法,而不是修改函数的实参 375 | 376 | ```javascript 377 | // really bad 378 | function handleThings(opts) { 379 | opts = opts || {}; 380 | } 381 | 382 | // still bad 383 | function handleThings(opts) { 384 | if (opts === void 0) { 385 | opts = {}; 386 | } 387 | } 388 | 389 | // good 390 | function handleThings(opts = {}) { 391 | // ... 392 | } 393 | ``` 394 | ## 六、箭头函数 Arrow Functions 395 | > 当必须使用函数表达式时(例如传递一个匿名函数时),请使用箭头函数 396 | 397 | 箭头函数提供了更简洁的语法,并且箭头函数中 this 对象的指向是不变的,this 对象绑定定义时所在的对象,这通常是我们想要的。如果该函数的逻辑非常复杂,请将该函数提取为一个函数声明。 398 | 399 | ```javascript 400 | // bad 401 | "use strict"; 402 | var fn = function fn(v) { 403 | return console.log(v); 404 | }; 405 | 406 | // good 407 | var fn= (v=>console.log(v)); 408 | ``` 409 | > 箭头函数总是用括号包裹参数,省略括号只适用于单个参数,并且还降低了程序的可读性 410 | 411 | ```javascript 412 | // bad 413 | [1, 2, 3].forEach(x => x * x); 414 | 415 | // good 416 | [1, 2, 3].forEach((x) => x * x); 417 | ``` 418 | 419 | > 立即执行的匿名函数 420 | 421 | ```javascript 422 | // 函数表达式 423 | // immediately-invoked function expression (IIFE) 424 | // good,看起来就很厉害 425 | (() => { 426 | console.log('Welcome to the Internet. Please follow me.'); 427 | })(); 428 | ``` 429 | 430 | ## 七、对象 431 | 432 | > 使用对象字面量创建对象 433 | 434 | 435 | ```javascript 436 | // bad 437 | var item = new Object(); 438 | 439 | // good 440 | var item = {}; 441 | ``` 442 | > 不要使用保留字(reserved words)作为键,否则在 IE8 下将出错 443 | 444 | ```javascript 445 | // bad 446 | var superman = { 447 | class: 'superhero', 448 | default: { clark: 'kent' }, 449 | private: true 450 | }; 451 | 452 | // good 453 | var superman = { 454 | klass: 'superhero', 455 | defaults: { clark: 'kent' }, 456 | hidden: true 457 | }; 458 | ``` 459 | 460 | > 创建对象时使用计算的属性名,而不要在创建对象后使用对象的动态特性,这样可以在同一个位置定义对象的所有属性。 461 | 462 | ```javascript 463 | function getKey(k) { 464 | return `a key named ${k}`; 465 | } 466 | 467 | // bad 468 | const obj = { 469 | id: 5, 470 | name: 'San Francisco' 471 | }; 472 | obj[getKey('enabled')] = true; 473 | 474 | // good 475 | const obj = { 476 | id: 5, 477 | name: 'San Francisco', 478 | [getKey('enabled')]: true 479 | }; 480 | ``` 481 | 482 | > 使用定义对象方法的简短形式 483 | 484 | ```javascript 485 | // bad 486 | const atom = { 487 | value: 1, 488 | 489 | addValue: function (value) { 490 | return atom.value + value; 491 | } 492 | }; 493 | 494 | // good 495 | const atom = { 496 | value: 1, 497 | 498 | addValue(value) { 499 | return atom.value + value; 500 | } 501 | }; 502 | ``` 503 | 504 | > 使用定义对象属性的简短形式,书写起来更加简单,并且可以自描述。这里和es5有些不同,需要注意下 505 | 506 | ```javascript 507 | const lukeSkywalker = 'Luke Skywalker'; 508 | 509 | // bad 510 | const obj = { 511 | lukeSkywalker: lukeSkywalker 512 | }; 513 | 514 | // good 515 | const obj = { 516 | lukeSkywalker 517 | }; 518 | ``` 519 | 520 | 521 | > 将所有简写的属性写在对象定义的最顶部,这样可以更加方便地知道哪些属性使用了简短形式。 522 | 523 | ```javascript 524 | const anakinSkywalker = 'Anakin Skywalker'; 525 | const lukeSkywalker = 'Luke Skywalker'; 526 | 527 | // bad 528 | const obj = { 529 | episodeOne: 1, 530 | twoJedisWalkIntoACantina: 2, 531 | lukeSkywalker, 532 | episodeThree: 3, 533 | mayTheFourth: 4, 534 | anakinSkywalker 535 | }; 536 | 537 | // good 538 | const obj = { 539 | lukeSkywalker, 540 | anakinSkywalker, 541 | episodeOne: 1, 542 | twoJedisWalkIntoACantina: 2, 543 | episodeThree: 3, 544 | mayTheFourth: 4 545 | }; 546 | ``` 547 | 548 | ## 八、类 549 | > 总是使用 class 关键字,避免直接修改 prototype,class 语法更简洁,也更易理解。 550 | 551 | ```javascript 552 | // bad 553 | function Queue(contents = []) { 554 | this._queue = [...contents]; 555 | } 556 | Queue.prototype.pop = function() { 557 | const value = this._queue[0]; 558 | this._queue.splice(0, 1); 559 | return value; 560 | } 561 | 562 | // good 563 | class Queue { 564 | constructor(contents = []) { 565 | this._queue = [...contents]; 566 | } 567 | pop() { 568 | const value = this._queue[0]; 569 | this._queue.splice(0, 1); 570 | return value; 571 | } 572 | } 573 | ``` 574 | > 类名与花括号须保留一个空格间距,类中的方法定义时,括号 ) 也须与花括号 { 保留一个空格间距 575 | 576 | ```javascript 577 | // not good 578 | class Foo{ 579 | constructor(){ 580 | // constructor 581 | } 582 | sayHi() { 583 | // 仅保留一个空格间距 584 | } 585 | } 586 | 587 | // good 588 | class Foo { 589 | constructor() { 590 | // constructor 591 | } 592 | sayHi() { 593 | // 仅保留一个空格间距 594 | } 595 | } 596 | ``` 597 | > 定义类时,方法的顺序如下: 598 | 599 | - constructor 600 | - public get/set 公用访问器,set只能传一个参数 601 | - public methods 公用方法,公用相关命名使用小驼峰式写法(lowerCamelCase) 602 | - private get/set 私有访问器,私有相关命名应加上下划线 _ 为前缀 603 | - private methods 私有方法 604 | 605 | ```javascript 606 | // good 607 | class SomeClass { 608 | constructor() { 609 | // constructor 610 | } 611 | 612 | get aval() { 613 | // public getter 614 | } 615 | 616 | set aval(val) { 617 | // public setter 618 | } 619 | 620 | doSth() { 621 | // 公用方法 622 | } 623 | 624 | get _aval() { 625 | // private getter 626 | } 627 | 628 | set _aval() { 629 | // private setter 630 | } 631 | 632 | _doSth() { 633 | // 私有方法 634 | } 635 | } 636 | ``` 637 | > 如果不是class类,不使用new 638 | 639 | ```javascript 640 | // not good 641 | function Foo() { 642 | 643 | } 644 | const foo = new Foo(); 645 | 646 | // good 647 | class Foo { 648 | 649 | } 650 | const foo = new Foo(); 651 | ``` 652 | 653 | > 使用 extends 关键字来继承 654 | 655 | 这是一个内置的继承方式,并且不会破坏 instanceof 原型检查。 656 | 657 | ```javascript 658 | 659 | // bad 660 | const inherits = require('inherits'); 661 | function PeekableQueue(contents) { 662 | Queue.apply(this, contents); 663 | } 664 | inherits(PeekableQueue, Queue); 665 | PeekableQueue.prototype.peek = function() { 666 | return this._queue[0]; 667 | } 668 | 669 | // good 670 | class PeekableQueue extends Queue { 671 | peek() { 672 | return this._queue[0]; 673 | } 674 | } 675 | ``` 676 | 677 | ## 九、模块 678 | 总是在非标准的模块系统中使用标准的 import 和 export 语法,我们总是可以将标准的模块语法转换成支持特定模块加载器的语法。 679 | 680 | > 推荐使用import和export来做模块加载 681 | 682 | ```javascript 683 | // bad 684 | const AirbnbStyleGuide = require('./AirbnbStyleGuide'); 685 | module.exports = AirbnbStyleGuide.es6; 686 | 687 | // ok 688 | import AirbnbStyleGuide from './AirbnbStyleGuide'; 689 | export default AirbnbStyleGuide.es6; 690 | 691 | // best 692 | import { es6 } from './AirbnbStyleGuide'; 693 | export default es6; 694 | ``` 695 | > import / export 后面采用花括号{ }引入模块的写法时,建议在花括号内左右各保留一个空格 696 | 697 | ```javascript 698 | // not good 699 | import {lightRed} from './colors'; 700 | import { lightRed} from './colors'; 701 | 702 | // good 703 | import { lightRed } from './colors'; 704 | ``` 705 | > 不要使用通配符 * 的 import,这样确保了一个模块只有一个默认的 export 项 706 | 707 | ```javascript 708 | // bad 709 | import * as AirbnbStyleGuide from './AirbnbStyleGuide'; 710 | 711 | // good 712 | import AirbnbStyleGuide from './AirbnbStyleGuide'; 713 | ``` 714 | > 不要直接从一个 import 上 export 715 | 716 | 虽然一行代码看起来更简洁,但是有一个明确的 import 和一个明确的 export 使得代码行为更加明确。 717 | 718 | ```javascript 719 | // bad 720 | // filename es6.js 721 | export default { es6 } from './airbnbStyleGuide'; 722 | 723 | // good 724 | // filename es6.js 725 | import { es6 } from './AirbnbStyleGuide'; 726 | export default es6; 727 | ``` 728 | > 多变量要导出时应采用对象解构形式 729 | 730 | ```javascript 731 | // not good 732 | export const a= 'a'; 733 | export const b= 'b'; 734 | 735 | // good 736 | export const a= 'a'; 737 | export const b= 'b'; 738 | 739 | export default { a, b }; 740 | ``` 741 | > 导出单一一个类时,确保你的文件名就是你的类名 742 | 743 | ```javascript 744 | 745 | // file contents 746 | class CheckBox { 747 | // ... 748 | } 749 | module.exports = CheckBox; 750 | 751 | // in some other file 752 | // bad 753 | const CheckBox = require('./checkBox'); 754 | 755 | // bad 756 | const CheckBox = require('./check_box'); 757 | 758 | // good 759 | const CheckBox = require('./CheckBox'); 760 | ``` 761 | 762 | > 导出一个默认小驼峰命名的函数时,文件名应该就是导出的方法名 763 | 764 | ```javascript 765 | function makeStyleGuide() { 766 | } 767 | 768 | export default makeStyleGuide; 769 | ``` 770 | 771 | > 导出单例、函数库或裸对象时,使用大驼峰命名规则 772 | 773 | ```javascript 774 | const AirbnbStyleGuide = { 775 | es6: { 776 | } 777 | }; 778 | 779 | export default AirbnbStyleGuide; 780 | ``` 781 | 782 | ## 十、Iterators 和 Generators 783 | 784 | > Iterators。性能比较差,对于数组来说大致与Array.prototype.forEach相当,比不过原生的for循环,而且用起来比较麻烦,数组提供了for...of,对象提供了for...in,不推荐使用迭代器。 785 | 786 | ```javascript 787 | const numbers = [1, 2, 3, 4, 5]; 788 | 789 | // bad 790 | var iterator = numbers[Symbol.iterator](); 791 | var result = iterator.next(); 792 | let sum = 0; 793 | while (!result.done) { 794 | sum += result.value; 795 | result = iterator.next(); 796 | } 797 | 798 | // good 799 | let sum = 0; 800 | for (let num of numbers) { 801 | sum += num; 802 | } 803 | sum === 15; 804 | 805 | // good 806 | let sum = 0; 807 | numbers.forEach((num) => sum += num); 808 | sum === 15; 809 | 810 | // best (use the functional force) 811 | const sum = numbers.reduce((total, num) => total + num, 0); 812 | sum === 15; 813 | ``` 814 | 815 | > generators。不推荐使用,或者非常谨慎地使用。 816 | 817 | 生成器不是用来写异步的,虽然确实有这样一个效果,但这仅仅是一种Hack。异步在未来一定是属于async和await这两个关键字的,但太多人眼里生成器就是写异步用的,这会导致滥用。暂时推荐用promise来实现异步。 818 | 819 | ## 十一、属性访问 820 | 821 | > 使用点 . 操作符来访问常量属性 822 | 823 | ```javascript 824 | const luke = { 825 | jedi: true, 826 | age: 28 827 | }; 828 | 829 | // bad 830 | const isJedi = luke['jedi']; 831 | 832 | // good 833 | const isJedi = luke.jedi; 834 | ``` 835 | 836 | > 使用中括号[] 操作符来访问变量属性 837 | 838 | ```javascript 839 | var luke = { 840 | jedi: true, 841 | age: 28 842 | }; 843 | 844 | function getProp(prop) { 845 | return luke[prop]; 846 | } 847 | 848 | var isJedi = getProp('jedi'); 849 | ``` 850 | 851 | ## 十二、map + set + weakmap + weakset 数据结构 852 | 853 | > 新加的集合类型,提供了更加方便的获取属性值的方法,可以检查某个属性是属于原型链上还是当前对象的,并用获取对象的set和get方法 854 | 855 | 856 | > 但是,推荐使用weakmap和weakset,而不是map和set,除非必须使用。普通集合会阻止垃圾回收器对这些作为属性键存在的对象的回收,有造成内存泄漏的危险 857 | 858 | ```javascript 859 | // not good, Maps 860 | var wm = new Map(); 861 | wm.set(key, { extra: 42 }); 862 | wm.size === 1 863 | 864 | // not good, Sets 865 | var ws = new Set(); 866 | ws.add({ data: 42 }); 867 | 868 | // good, Weak Maps 869 | var wm = new WeakMap(); 870 | wm.set(key, { extra: 42 }); 871 | wm.size === undefined 872 | 873 | // good, Weak Sets 874 | var ws = new WeakSet(); 875 | ws.add({ data: 42 });//因为添加到ws的这个临时对象没有其他变量引用它,所以ws不会保存它的值,也就是说这次添加其实没有意思 876 | 877 | // not good 878 | let object = {}, 879 | object.hasOwnProperty(key) 880 | 881 | // good 882 | let object = new WeakSet(); 883 | object.has(key) === true; 884 | ``` 885 | 886 | - 当你的元素或者键值有可能不是字符串时,推荐使用WeakMap和WeakSet。 887 | 888 | ```javascript 889 | // bad 890 | var obj = { 3:'value' }; 891 | 892 | // good 893 | var ws = new WeakSet(); 894 | ws.add(3, 'value'); 895 | ``` 896 | 897 | - 有移除操作的需求时,使用WeakMap和WeakSet。 898 | 899 | ```javascript 900 | // bad 901 | var obj = { 'key':'value' }; 902 | delete obj.key; 903 | 904 | // good 905 | var ws = new WeakSet(); 906 | ws.add('key', 'value'); 907 | ws.remove('key'); 908 | ``` 909 | 910 | - 当仅需要一个不可重复的集合时,使用WeakSet优先于普通对象,而不要使用{foo: true}这样的对象。 911 | 912 | ```javascript 913 | // bad 914 | var obj = { 'key':'value' }; 915 | 916 | // good 917 | var ws = new WeakSet(); 918 | ws.add('key', 'value'); 919 | ``` 920 | 921 | - 当需要遍历功能时,使用WeakMap和WeakSet,因为其可以简单地使用for..of进行遍历,性能更高 922 | 923 | ```javascript 924 | // bad 925 | var obj = { key:'value', key1: 'value1' }; 926 | for(var key in obj){ 927 | } 928 | 929 | // good 930 | var ws = new WeakSet(); 931 | ws.add('key', 'value').add('key1', 'value1'); 932 | for(var key of ws){ 933 | } 934 | ``` 935 | 936 | ## 十三、promise、symbols、proxies 937 | 938 | > promise是一种异步处理模式。发promise申明和调用分开,推荐异步方式使用Promise。 939 | 940 | ```javascript 941 | 942 | // not good 943 | (new Promise(resolve, reject){}) 944 | .then(cunction(){},function(){}) 945 | .then(); 946 | 947 | // good 948 | var promise = new Primise(function(resolve, reject){}); 949 | promise 950 | .then(function(){},function(){]}) 951 | .then(); 952 | 953 | ``` 954 | 955 | > symbol用于对象的键和私有属性,使用过于复杂,没有使用必要,容易扰乱外层作用域。总之不要使用 956 | 957 | ```javascript 958 | // good 959 | function MyClass(privateData) { 960 | let key = privateData; 961 | } 962 | 963 | //not good 964 | const key = Symbol('key'); 965 | function MyClass(privateData) { 966 | this[key] = privateData; 967 | } 968 | 969 | const object = new MyClass("hello") 970 | object['key'] === undefined //无法访问该属性,因为是私有的 971 | ``` 972 | 973 | > Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作,没有特别要注意的,尽情用吧。 974 | 975 | 976 | ## 十四、不要使用统一码 977 | > 字符串支持新的Unicode文本形式,也增加了新的正则表达式修饰符u来处理码位,但是一般不要这样处理,会减低程序可读性且处理统一码速度会降低 978 | 979 | ```javascript 980 | // not good 981 | '字符串'.length == 6 982 | 983 | // 新加的:正则支持统一码'u', 但仍建议不使用 984 | // not good 985 | '字符串'.match(/./u)[0].length == 6 986 | '字符串'.codePointAt(0) == 0x20BB7 987 | 988 | ``` 989 | 990 | ## 十五、进制数支持 991 | 992 | > 加入对二进制(b)和八进制(o)字面量的支持。该特性可以使用 993 | 994 | ```javascript 995 | // ok 996 | 0b111110111 === 503 // true 997 | 0o767 === 503 // true 998 | ``` 999 | 1000 | ## 十六、不建议使用reflect对象和tail calls尾调用 1001 | > 没有使用的必要性 1002 | 1003 | (继续完善) 1004 | 1005 | [源规范](https://ouvens.github.io/frontend-javascript/2015/11/24/es6-code-style-for-node.html) 1006 | 1007 | 参考: 1008 | http://bubkoo.com/2015/04/05/javascript-style-guide/?utm_source=tuicool 1009 | 1010 | https://github.com/gf-rd/es6-coding-style#%E5%A3%B0%E6%98%8E 1011 | 1012 | https://github.com/ES-CN/es6features/blob/master/README.md?utm_source=tuicool&utm_medium=referral --------------------------------------------------------------------------------