• ES6编码规范全部(含node部分)



    http://my.oschina.net/zhangstephen/blog/541289


    Ecmascript6 规范(含node部分)

    • 一、类型规范
    • 二、字符串模板
    • 三、数组类型
    • 四、解构类型
    • 五、函数
    • 六、arrow箭头函数
    • 七、对象
    • 八、类
    • 九、模块
    • 十、Iterators 和 Generators
    • 十一、属性访问
    • 十二、map + set + weakmap + weakset 数据结构
    • 十三、promise、symbols、proxies
    • 十四、统一码
    • 十五、进制数支持
    • 十六、不建议使用reflect对象和tail calls尾调用

    一、类型规范

    对于常量或不修改的变量声明使用const,对于只在当前作用域下有效的变量,应使用let,全局变量使用var。将所有 const 变量放在一起,然后将所有 let 变量放在一起

    
    const foo = 1;
    
    let foo1 = 2;
    let bar = foo;
    bar = 9;
    foo1 = 3;
    
    console.log(foo, bar); // => 1, 9
    console.log(foo, bar, str); // => 1, 9,'ouven'
    

    const和let使用时注意,let 和 const 都是块作用域的

    
    // const and let only exist in the blocks they are defined in.
    {
      let a = 1;
      const b = 1;
    }
    console.log(a); // ReferenceError
    console.log(b); // ReferenceError
    

    二、字符串

    使用单引号 '

    
    // bad
    var name = "Bob Parr";
    
    // good
    var name = 'Bob Parr';
    
    // bad
    var fullName = "Bob " + this.lastName;
    
    // good
    var fullName = 'Bob ' + this.lastName;
    

    超过80个字符的字符串应该使用字符串连接换行注:如果过度使用长字符串连接可能会对性能有影响。jsPerf & Discussion

    
    // bad
    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.';
    
    // bad
    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.';
    
    
    // good
    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.';
    

    编程构建字符串时,使用字符串模板而不是字符串连接

    模板给你一个可读的字符串,简洁的语法与适当的换行和字符串插值特性。

    
    // 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}?`;
    }
    

    三、数组类型

    使用字面量语法创建数组

    // bad
    const items = new Array();
    
    // good
    const items = [];
    

    如果你不知道数组的长度,使用 push

    const someStack = [];
    
    // bad
    someStack[someStack.length] = 'abracadabra';
    
    // good
    someStack.push('abracadabra');
    

    使用 ... 来拷贝数组,不要使用 Array.from、Array.of等数组的新的内置API,Array新api用于适合的场景

    // bad
    const len = items.length;
    const itemsCopy = [];
    let i;
    
    for (i = 0; i < len; i++) {
      itemsCopy[i] = items[i];
    }
    
    // good
    const itemsCopy = [...items];
    
    // not good
    const foo = [1,2,3];
    const nodes = Array.from(foo);
    

    四、解构 Destructuring

    使用对象的多个属性时请建议使用对象的解构赋值,解构赋值避免了为这些属性创建临时变量或对象。即使转化成es5都是一样的

    嵌套结构的对象层数不能超过3层

    // not good
    let obj = {
      'one': [
        {
          'newTwo': [
            {
              'three': [
                'four': '太多层了,头晕晕'
              ]
            }
          ]
        }
      ]
    };
    
    // good
    let obj = {
      'one': [
        'two',
        {
          'twoObj': '结构清晰'
        }
      ]
    };
    

    解构语句中统一不使用圆括号

    // not good
    [(a)] = [11]; // a未定义
    let { a: (b) } = {}; // 解析出错
    
    
    // good
    let [a, b] = [11, 22];
    

    对象解构

    对象解构元素与顺序无关对象指定默认值时仅对恒等于undefined ( !== null ) 的情况生效

    若函数形参为对象时,使用对象解构赋值

    // not good
    function someFun(opt) {
      let opt1 = opt.opt1;
      let opt2 = opt.opt2;
      console.log(op1);
    }
    
    
    // good
    function someFun(opt) {
      let { opt1, opt2 } = opt;
      console.log(`$(opt1) 加上 $(opt2)`);
    }
    
    function someFun({ opt1, opt2 }) {
      console.log(opt1);
    }
    

    若函数有多个返回值时,使用对象解构,不使用数组解构,避免添加顺序的问题

    // not good
    function anotherFun() {
      const one = 1, two = 2, three = 3;
      return [one, two, three];
    }
    const [one, three, two] = anotherFun(); // 顺序乱了
    // one = 1, two = 3, three = 2
    
    
    // good
    function anotherFun() {
      const one = 1, two = 2, three = 3;
      return { one, two, three };
    }
    const { one, three, two } = anotherFun(); // 不用管顺序
    // one = 1, two = 2, three = 3
    

    已声明的变量不能用于解构赋值(语法错误)

    // 语法错误
    let a;
    { a } = { b: 123};
    

    数组解构时数组元素与顺序相关

    例如交换数组两个元素的值

    let x = 1;
    let y = 2;
    
    // not good
    let temp;
    temp = x;
    x = y;
    y = temp;
    
    
    // good
    [x, y] = [y, x]; // 交换变量
    

    将数组成员赋值给变量时,使用数组解构

    const arr = [1, 2, 3, 4, 5];
    
    // not good
    const one = arr[0];
    const two = arr[1];
    
    
    // good
    const [one, two] = arr;
    

    函数有多个返回值时使用对象解构,而不是数组解构。

    这样你就可以随时添加新的返回值或任意改变返回值的顺序,而不会导致调用失败。

    
    function processInput(input) {
        // then a miracle occurs
        return [left, right, top, bottom];
      }
    
      // the caller needs to think about the order of return data
      const [left, __, top] = processInput(input);
    
      // good
      function processInput(input) {
        // then a miracle occurs
        return { left, right, top, bottom };
      }
    
      // the caller selects only the data they need
      const { left, right } = processInput(input);
    

    五、函数

    使用函数声明而不是函数表达式

    函数声明拥有函数名,在调用栈中更加容易识别。并且,函数声明会整体提升,而函数表达式只会提升变量本身。这条规则也可以这样描述,始终使用箭头函数来代替函数表达式。

    // bad
    const foo = function () {
    };
    
    // good
    function foo() {
    }
    

    绝对不要在一个非函数块(if,while,等等)里声明一个函数,把那个函数赋给一个变量。浏览器允许你这么做,但是它们解析不同注:ECMA-262 把 块 定义为一组语句,函数声明不是一个语句。阅读 ECMA-262 对这个问题的说明

    // bad
    if (currentUser) {
      function test() {
        console.log('Nope.');
      }
    }
    
    // good
    if (currentUser) {
      var test = function test() {
        console.log('Yup.');
      };
    }
    

    绝对不要把参数命名为 arguments, 这将会覆盖函数作用域内传过来的 arguments 对象

    // bad
    function nope(name, options, arguments) {
      // ...stuff...
    }
    
    // good
    function yup(name, options, args) {
      // ...stuff...
    }
    

    永远不要使用 arguments,使用 ... 操作符来代替

    ... 操作符可以明确指定你需要哪些参数,并且得到的是一个真实的数组,而不是 arguments 这样的类数组对象。

    // bad
    function concatenateAll() {
      const args = Array.prototype.slice.call(arguments);
      return args.join('');
    }
    
    // good
    function concatenateAll(...args) {
      return args.join('');
    }
    

    使用函数参数默认值语法,而不是修改函数的实参

    // really bad
    function handleThings(opts) {
      opts = opts || {};
    }
    
    // still bad
    function handleThings(opts) {
      if (opts === void 0) {
        opts = {};
      }
    }
    
    // good
    function handleThings(opts = {}) {
      // ...
    }
    

    六、箭头函数 Arrow Functions

    当必须使用函数表达式时(例如传递一个匿名函数时),请使用箭头函数

    箭头函数提供了更简洁的语法,并且箭头函数中 this 对象的指向是不变的,this 对象绑定定义时所在的对象,这通常是我们想要的。如果该函数的逻辑非常复杂,请将该函数提取为一个函数声明。

    // bad
    "use strict";
    var fn = function fn(v) {
      return console.log(v);
    };
    
    // good
    var fn= (v=>console.log(v));
    

    箭头函数总是用括号包裹参数,省略括号只适用于单个参数,并且还降低了程序的可读性

    // bad
    [1, 2, 3].forEach(x => x * x);
    
    // good
    [1, 2, 3].forEach((x) => x * x);
    

    立即执行的匿名函数

    // 函数表达式
    // immediately-invoked function expression (IIFE)
    // good,看起来就很厉害
    (() => {
      console.log('Welcome to the Internet. Please follow me.');
    })();
    

    七、对象

    使用对象字面量创建对象

    // bad
    var item = new Object();
    
    // good
    var item = {};
    

    不要使用保留字(reserved words)作为键,否则在 IE8 下将出错

    // bad
    var superman = {
      class: 'superhero',
      default: { clark: 'kent' },
      private: true
    };
    
    // good
    var superman = {
      klass: 'superhero',
      defaults: { clark: 'kent' },
      hidden: true
    };
    

    创建对象时使用计算的属性名,而不要在创建对象后使用对象的动态特性,这样可以在同一个位置定义对象的所有属性。

    function getKey(k) {
        return `a key named ${k}`;
      }
    
      // bad
      const obj = {
        id: 5,
        name: 'San Francisco'
      };
      obj[getKey('enabled')] = true;
    
      // good
      const obj = {
        id: 5,
        name: 'San Francisco',
        [getKey('enabled')]: true
      };
    

    使用定义对象方法的简短形式

    // bad
    const atom = {
      value: 1,
    
      addValue: function (value) {
        return atom.value + value;
      }
    };
    
    // good
    const atom = {
      value: 1,
    
      addValue(value) {
        return atom.value + value;
      }
    };
    

    使用定义对象属性的简短形式,书写起来更加简单,并且可以自描述。这里和es5有些不同,需要注意下

    const lukeSkywalker = 'Luke Skywalker';
    
      // bad
      const obj = {
        lukeSkywalker: lukeSkywalker
      };
    
      // good
      const obj = {
        lukeSkywalker
      };
    

    将所有简写的属性写在对象定义的最顶部,这样可以更加方便地知道哪些属性使用了简短形式。

    const anakinSkywalker = 'Anakin Skywalker';
    const lukeSkywalker = 'Luke Skywalker';
    
    // bad
    const obj = {
      episodeOne: 1,
      twoJedisWalkIntoACantina: 2,
      lukeSkywalker,
      episodeThree: 3,
      mayTheFourth: 4,
      anakinSkywalker
    };
    
    // good
    const obj = {
      lukeSkywalker,
      anakinSkywalker,
      episodeOne: 1,
      twoJedisWalkIntoACantina: 2,
      episodeThree: 3,
      mayTheFourth: 4
    };
    

    八、类

    总是使用 class 关键字,避免直接修改 prototype,class 语法更简洁,也更易理解。

    // bad
    function Queue(contents = []) {
      this._queue = [...contents];
    }
    Queue.prototype.pop = function() {
      const value = this._queue[0];
      this._queue.splice(0, 1);
      return value;
    }
    
    // good
    class Queue {
      constructor(contents = []) {
        this._queue = [...contents];
      }
      pop() {
        const value = this._queue[0];
        this._queue.splice(0, 1);
        return value;
      }
    }
    

    类名与花括号须保留一个空格间距,类中的方法定义时,括号 ) 也须与花括号 { 保留一个空格间距

    // not good
    class Foo{
      constructor(){
        // constructor
      }
      sayHi()    {
        // 仅保留一个空格间距
      }
    }
    
    // good
    class Foo {
      constructor() {
        // constructor
      }
      sayHi() {
        // 仅保留一个空格间距
      }
    }
    

    定义类时,方法的顺序如下:

    • constructor
    • public get/set 公用访问器,set只能传一个参数
    • public methods 公用方法,公用相关命名使用小驼峰式写法(lowerCamelCase)
    • private get/set 私有访问器,私有相关命名应加上下划线 _ 为前缀
    • private methods 私有方法
    // good
    class SomeClass {
      constructor() {
        // constructor
      }
    
      get aval() {
        // public getter
      }
    
      set aval(val) {
        // public setter
      }
    
      doSth() {
        // 公用方法
      }
    
      get _aval() {
        // private getter
      }
    
      set _aval() {
        // private setter
      }
    
      _doSth() {
        // 私有方法
      }
    }
    

    如果不是class类,不使用new

    // not good
    function Foo() {
    
    }
    const foo = new Foo();
    
    // good
    class Foo {
    
    }
    const foo = new Foo();
    

    使用 extends 关键字来继承

    这是一个内置的继承方式,并且不会破坏 instanceof 原型检查。

    
    // bad
      const inherits = require('inherits');
      function PeekableQueue(contents) {
        Queue.apply(this, contents);
      }
      inherits(PeekableQueue, Queue);
      PeekableQueue.prototype.peek = function() {
        return this._queue[0];
      }
    
      // good
      class PeekableQueue extends Queue {
        peek() {
          return this._queue[0];
        }
      }
    

    九、模块

    总是在非标准的模块系统中使用标准的 import 和 export 语法,我们总是可以将标准的模块语法转换成支持特定模块加载器的语法。

    推荐使用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;
    

    import / export 后面采用花括号{ }引入模块的写法时,建议在花括号内左右各保留一个空格

    // not good
    import {lightRed} from './colors';
    import { lightRed} from './colors';
    
    // good
    import { lightRed } from './colors';
    

    不要使用通配符 * 的 import,这样确保了一个模块只有一个默认的 export 项

    // bad
    import * as AirbnbStyleGuide from './AirbnbStyleGuide';
    
    // good
    import AirbnbStyleGuide from './AirbnbStyleGuide';
    

    不要直接从一个 import 上 export

    虽然一行代码看起来更简洁,但是有一个明确的 import 和一个明确的 export 使得代码行为更加明确。

    // bad
    // filename es6.js
    export default { es6 } from './airbnbStyleGuide';
    
    // good
    // filename es6.js
    import { es6 } from './AirbnbStyleGuide';
    export default es6;
    

    多变量要导出时应采用对象解构形式

    // not good
    export const a= 'a';
    export const b= 'b';
    
    // good
    export const a= 'a';
    export const b= 'b';
    
    export default { a, b };
    

    导出单一一个类时,确保你的文件名就是你的类名

    
    // file contents
    class CheckBox {
      // ...
    }
    module.exports = CheckBox;
    
    // in some other file
    // bad
    const CheckBox = require('./checkBox');
    
    // bad
    const CheckBox = require('./check_box');
    
    // good
    const CheckBox = require('./CheckBox');
    

    导出一个默认小驼峰命名的函数时,文件名应该就是导出的方法名

    function makeStyleGuide() {
    }
    
    export default makeStyleGuide;
    

    导出单例、函数库或裸对象时,使用大驼峰命名规则

    const AirbnbStyleGuide = {
      es6: {
      }
    };
    
    export default AirbnbStyleGuide;
    

    十、Iterators 和 Generators

    Iterators。性能比较差,对于数组来说大致与Array.prototype.forEach相当,比不过原生的for循环,而且用起来比较麻烦,数组提供了for...of,对象提供了for...in,不推荐使用迭代器。

    const numbers = [1, 2, 3, 4, 5];
    
    // bad
    var iterator = numbers[Symbol.iterator]();  
    var result = iterator.next();
    let sum = 0;
    while (!result.done) {
      sum += result.value;
      result = iterator.next();  
    }  
    
    // good
    let sum = 0;
    for (let num of numbers) {
      sum += num;
    }
    sum === 15;
    
    // good
    let sum = 0;
    numbers.forEach((num) => sum += num);
    sum === 15;
    
    // best (use the functional force)
    const sum = numbers.reduce((total, num) => total + num, 0);
    sum === 15;
    

    generators。不推荐使用,或者非常谨慎地使用。

    生成器不是用来写异步的,虽然确实有这样一个效果,但这仅仅是一种Hack。异步在未来一定是属于async和await这两个关键字的,但太多人眼里生成器就是写异步用的,这会导致滥用。暂时推荐用promise来实现异步。

    十一、属性访问

    使用点 . 操作符来访问常量属性

    const luke = {
      jedi: true,
      age: 28
    };
    
    // bad
    const isJedi = luke['jedi'];
    
    // good
    const isJedi = luke.jedi;
    

    使用中括号[] 操作符来访问变量属性

    var luke = {
      jedi: true,
      age: 28
    };
    
    function getProp(prop) {
      return luke[prop];
    }
    
    var isJedi = getProp('jedi');
    

    十二、map + set + weakmap + weakset 数据结构

    新加的集合类型,提供了更加方便的获取属性值的方法,可以检查某个属性是属于原型链上还是当前对象的,并用获取对象的set和get方法

    但是,推荐使用weakmap和weakset,而不是map和set,除非必须使用。普通集合会阻止垃圾回收器对这些作为属性键存在的对象的回收,有造成内存泄漏的危险

    // not good, Maps
    var wm = new Map();
    wm.set(key, { extra: 42 });
    wm.size === 1
    
    // not good, Sets
    var ws = new Set();
    ws.add({ data: 42 });
    
    // good, Weak Maps
    var wm = new WeakMap();
    wm.set(key, { extra: 42 });
    wm.size === undefined
    
    // good, Weak Sets
    var ws = new WeakSet();
    ws.add({ data: 42 });//因为添加到ws的这个临时对象没有其他变量引用它,所以ws不会保存它的值,也就是说这次添加其实没有意思
    
    // not good
    let object = {},
    object.hasOwnProperty(key)
    
    // good
    let object = new WeakSet();
    object.has(key) === true;
    
    • 当你的元素或者键值有可能不是字符串时,推荐使用WeakMap和WeakSet。
    // bad
    var obj = { 3:'value' };
    
    // good
    var ws = new WeakSet();
    ws.add(3, 'value');
    
    • 有移除操作的需求时,使用WeakMap和WeakSet。
    // bad
    var obj = { 'key':'value' };
    delete obj.key;
    
    // good
    var ws = new WeakSet();
    ws.add('key', 'value');
    ws.remove('key');
    
    • 当仅需要一个不可重复的集合时,使用WeakSet优先于普通对象,而不要使用{foo: true}这样的对象。
    // bad
    var obj = { 'key':'value' };
    
    // good
    var ws = new WeakSet();
    ws.add('key', 'value');
    
    • 当需要遍历功能时,使用WeakMap和WeakSet,因为其可以简单地使用for..of进行遍历,性能更高
    // bad
    var obj = { key:'value', key1: 'value1' };
    for(var key in obj){
    }
    
    // good
    var ws = new WeakSet();
    ws.add('key', 'value').add('key1', 'value1');
    for(var key of ws){
    }
    

    十三、promise、symbols、proxies

    promise是一种异步处理模式。发promise申明和调用分开,推荐异步方式使用Promise。

    
    // not good
    (new Promise(resolve, reject){})
      .then(cunction(){},function(){})
      .then();
    
    // good
    var promise = new Primise(function(resolve, reject){});
    promise
      .then(function(){},function(){]})
      .then();
    

    symbol用于对象的键和私有属性,使用过于复杂,没有使用必要,容易扰乱外层作用域。总之不要使用

    // good
    function MyClass(privateData) {
      let key = privateData;
    }
    
    //not good
    const key = Symbol('key');
    function MyClass(privateData) {
      this[key] = privateData;
    }
    
    const object = new MyClass("hello")
    object['key'] === undefined //无法访问该属性,因为是私有的
    

    Proxy可以监听对象身上发生了什么事情,并在这些事情发生后执行一些相应的操作,没有特别要注意的,尽情用吧。

    十四、不要使用统一码

    字符串支持新的Unicode文本形式,也增加了新的正则表达式修饰符u来处理码位,但是一般不要这样处理,会减低程序可读性且处理统一码速度会降低

    // not good
    '字符串'.length == 6
    
    // 新加的:正则支持统一码'u', 但仍建议不使用
    // not good
    '字符串'.match(/./u)[0].length == 6
    '字符串'.codePointAt(0) == 0x20BB7
    

    十五、进制数支持

    加入对二进制(b)和八进制(o)字面量的支持。该特性可以使用

    // ok
    0b111110111 === 503 // true
    0o767 === 503 // true
    

    十六、不建议使用reflect对象和tail calls尾调用

    没有使用的必要性

    参考:

    http://bubkoo.com/2015/04/05/javascript-style-guide/?utm_source=tuicoolhttps://github.com/gf-rd/es6-coding-style#%E5%A3%B0%E6%98%8Ehttps://github.com/ES-CN/es6features/blob/master/README.md?utm_source=tuicool&utm_medium=referral

    github地址:https://github.com/ouvens/ecmaScript-2015-babel-rules


  • 相关阅读:
    【JavaScript数据结构系列】04-优先队列PriorityQueue
    【JavaScript数据结构系列】02-栈Stack
    【JavaScript数据结构系列】01-数组Array
    【JavaScript数据结构系列】00-开篇
    2019个人年度总结
    批处理·命令行中常用的操作
    flutter 环境出错后排查
    [图解算法]线性时间选择Linear Select——<递归与分治策略>
    阿里云轻量应用服务器——配置MySQL远程连接(踩坑,LAMP+CentOS)
    [知识复习] C语言文件读写
  • 原文地址:https://www.cnblogs.com/ztguang/p/12646787.html
Copyright © 2020-2023  润新知