Js ES6编码规范入门百科_规范基础知识

简介本章节讨论使用ES6编码风格到代码中需要注意的点。通过记住这些关键点,可以让我们写出更优美的、可读性更强的JavaScript E6风格的代码。1、块级作用域1.1、let取代varES6 提出了两个新的声明变量的命令: let 和 const。其中,let可以完全取代var,因为两者语义相同,而且let没有副作用。var命令存在变量提升的特性,而let

Js ES6编码规范入门百科

简介

本章节讨论使用ES6编码风格到代码中需要注意的点。通过记住这些关键点,可以让我们写出更优美的、可读性更强的JavaScript E6风格的代码。

Js ES6编码规范入门百科_规范基础知识

1、块级作用域

1.1、let取代var

ES6 提出了两个新的声明变量的命令: let 和 const。其中,let可以完全取代var,因为两者语义相同,而且let没有副作用。

var命令存在变量提升的特性,而let没有这个命令。

1.2、全局常量和线程安全

在let和const之间,优先使用const。

let应出现在单线程模块代码内,而const则非常适合多线程。

    // bad
    var a = 1, b = 2, c = 3;

    // good
    const a = 1;
    const b = 2;
    const c = 3;

    // best
    const[a, b, c] = [1, 2, 3];

2、字符串

静态字符串一律使用单引号或者反引号,不推荐使用双引号。

动态字符串(字符串模板)使用反引号。

    // bad
    const a = "zhaoyi";
    const b = a + ", hello.";

    // little good
    const c = `zhaoyi`;

    // very good
    const a = 'zhaoyi';
    const b = `zhaoyi,${a}, I say your name twice`;

3、解构赋值

1、使用数组成员对变量进行赋值时,优先使用解构赋值。

    const arr = ['I', 'love', 'you'];

    // bad
    const one = arr[0];
    const two = arr[1];
    const three = arr[2];

    // good
    const [first, second, third] = arr;

    // test
    console.log(first, second, third);// I love you

2、函数的参数如果是对象的成员,优先使用解构赋值。

    // bad
    function getUserInfo(user){
        const name = user.name;
        const age = user.age;
    }

    // good
    function getUserInfo2(user){
        const {name, age} = user;
        console.log(name, age); // 
    }

    // test
    getUserInfo2({name: 'zhaoyi', age: 20}); // zhaoyi 20

3、如果函数返回多个值,优先使用对象的结构赋值,而不是数组的结构赋值。这样便于以后添加返回值,以及更改返回值的顺序。

    // bad
    function getInfo(input){
        return [left, right];
    }

    // good
    function getInfo2(input){
        return {left, right};
    }

    // 此处使用对象的解构赋值方式接收返回结果
    const {left, right} = getInfo2('test');

4、对象

1、单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。

    // bad
    const a1 = {k1: v1, k2: v2, k3: v3,};

    // good 
    const a2 = {k1: v1, k2: v2, k3: v3};

    // bad
    const b1 = {
        k1: v1,
        k2: v2
    };

    // good
    const b2 = {
        k1: v1,
        k2: v2,
    };

2、对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用assign方法。

    // bad
    const a = {};
    a.attr = 3;

    // if reshape anavoidable(若无可避免)
    const b = {};
    Object.assign(b, {atrr: 3});

    // good
    const c = {attr: null};
    c.attr = 3;

    // test
    console.log(a); //{attr: 3}
    console.log(b); //{attr: 3}
    console.log(c); //{attr: 3}

3、如果对象的属性名是动态的(所谓动态是指,需要通过计算得到),可以在创建对象的时候使用属性表达式定义。(此种情况在开发时,并不多见。)

5、数组

使用扩展运算符(…)复制数组。

    // bad
    function copyArr1(arr){
        const itemCopy = [];
        for (let index = 0; index < arr.length; index++) {
            itemCopy[index] = arr[index];
        }
        return itemCopy;
    }

    // good
    function copyArr2(arr){
        return [...arr];
    }

    // test
    const arr = ['z', 'y', 'z'];
    console.log(copyArr1(arr)); // ["z", "y", "z"]
    console.log(copyArr2(arr)); // ["z", "y", "z"]

使用Array.from 方法将类似数组的对象转为数组。

    const obj = { "0": "a", "1": "b", length: 2};
    const arr = Array.from(obj);
    
    // test
    console.log(arr); //  ["a", "b"]

6、函数

1、立即执行函数可以写成箭头函数的形式。

    (() => {
        console.log('this is a good night.');
    })();

2、在需要使用函数表达式的场合,尽量用箭头函数代替。因为这样可以更简洁,而且绑定了this。

    // bad
    const sayHello = ['a', 'b', 'c'].map(function (w){
        return 'Hello, ' + w;
    })
    
    // good 
    const sayHello2 = ['a', 'b', 'c'].map(w => {
        return 'Hello, ' + w;
    });

    // test
    console.log(sayHello2); //  ["Hello, a", "Hello, b", "Hello, c"]  

3、箭头函数取代Function.prototype.bind,不应再用self/_this/that绑定this.

    // bad
    const self = this;
    const boundMethod = function(...params){
        return method.apply(self, params);
    }

    // acceptable
    const boundMethod2 = method.bind(this);

    // best
    const boundMehod3 = (...params) => method.apply(this, params);

4、单行简单、无需复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应采用传统的函数写法。

5、所有配置项都应该集中在一个对象,放在到最后一个参数,布尔值不可以直接作为参数。

// bad
function divide(a, b, option = false){

}

// good
function divide(a, b, {option = false} = {}){

}

6、不要在函数体内使用arguments变量,使用rest运算符(…)代替。因为rest运算符可以显示声明我们想要获取的参数,而且arguments是一个类似数组的对象,而rest元素安抚可以提供一个真正的数组。

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

    // good
    function f2(...args){
        return args.join('-');
    }

    // test
    console.log(f1(1, 2, 3)); // 1-2-3
    console.log(f2(1, 2, 3)); // 1-2-3

7、使用默认值语法设置函数参数的默认值。

    // bad
    function handleThings(opts){
        opts = opts || {};
        // ...
    }

    // good
    function handleThings2(opts = {}){
        // ...
    }

7、Map结构

Map和Object给人的感觉是同一个数据类型,但是在实际语义还需要更为准确的区分,原则如下:

  • 模拟实体对象时,使用Object;
  • 只需要k-v键值对数据结构时,使用Map;

Map拥有内建的遍历机制(实现了Iterator结构)

    // Map拥有许多初始化方式,这里使用数组成员为两个长度的数组进行初始化(第一个元素为K,第二个元素为V)
    let map = new Map([['k1', 'I'], ['k2', 'love'], ['k3', 'your']]);

    // 遍历K
    for(const key of map.keys()){
        console.log(key);
        // k1
        // k2
        // k3
    }

    // 遍历V
    for (const value of map.values()) {
        console.log(value);
        // I
        // love
        // you
    }

    // 遍历K-V
    for (const item of map.entries()) {
        console.log(item);
        // ['k1', 'I']
        // ['k2', 'love']
        // ['k3', 'your']
    }

8、Class

1、总是用Class取代需要prototype的操作。因为Class的写法更简洁,更易于理解。接触过Java、C#比较多的朋友想必更喜欢这样的类语法方式。

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

    // good
    class Queue {
        constructor(contents = []){
            // 这里为什么不用this._queue = contents;呢?
            // 读过effective java的朋友想必知道一个规则:
            // 那就是在设计构造函数时,若传入的参数中有可变类型(对象、数组),
            // 则构造函数内部接收此参数时应使用这个对象的拷贝。
            // 这样可以避免外部参数对象的更改影响到类本身的实例。
            // 因此,此处的contents需要拷贝一个复制在进行赋值。
            this._queue = [...contents];
        }
        pop() {
            const value = this._queue[0];
            this._queue.splice(0, 1);
            return value;
        }
    }

    // test
    q = new Queue([1, 2, 3]);

    console.log(q.pop()); // 1
    console.log(q.pop()); // 2
    console.log(q.pop()); // 3
    console.log(q.pop()); // undefined

2、使用extends实现继承,因为这样可以更简单,不存在破坏instanceof运算的危险。

    // Queue为上一个例子的类
    class PeekQueue extends Queue{
        // ...
    }

9、模块

1、Module语法是JS模块的标准写法,要坚持使用这种写法。使用import取代require。

    // bad
    const ma = require('moduleA');
    const f1 = ma.f1;
    const f2 = ma.f2;

    // good
    import {f1, f2} from 'moduleA';

2、使用export取代module.export

    // bad
    module.exports = SomeObj;

    // good
    export default SomeObj; 

3、如果模块只有一个输出值,就使用 export default; 若有镀铬,就不要使用 export default, 不要同时使用 export default 和 普通的 export,虽然规则上允许此种编写代码的方式。

4、不要在模块中使用通配符,因为这样可以确保模块中有一个默认输出:export default。

    // bad
    import * as myObject './someModule';

    // good
    import myObject from './someModule';

5、如果模块默认输出一个函数,函数的首字母应该小写。

 function someFunction(){
     // ...
 }
 export default someFunction;

6、 如果模块默认输出一个对象,对象名的首字母应该大写。

const someObj = {
    // ...
}
export default SomeObj;

10、ESLint

前面说了那么多规则,其实只是规则范本的冰山一角,真正想要写出格式优美、符合主流厂商规范的代码,仅仅靠我们的自觉是不够的。

有没有什么类似软件编译工具检查代码正确性来检查代码编写规范的软件呢,答案是有的。

ESLint就是这样的一款检查工具。可以用于保证写出语法正确、风格统一的代码。

以下是安装ESLink的教程(确保您的环境已经安装了npm),当然,如果您使用一些脚手架工具(例如@vue-cli)等方式生成的项目,那么这样的项目都是提供了可选的eslint插件的。当前版本为: v6.6.0。该版本的eslint提供了更为简单的配置方式,可以参考 https://eslint.bootcss.com/docs/user-guide/getting-started/ 进行配置。以下是一个粗略的配置步骤

1、安装所需插件

$ npm install eslint -g

2、生成package.json文件

$ npm init

该方法会在当前目录生成package.json文件,该文件类似于环境的说明文件。

3、生成eslint配置文件

$ eslint --init

该命令会询问你使用哪种类型的配置(通过上下箭头选取)

  • 推荐选用json或者javascript类型,我这里使用的是JavaScript类型的配置文件
  • style guide选用airbnb。

其他的选项根据你的需要进行选取即可。完成选择之后,会自动下载所需要的依赖包。

生成的配置文件内容大致如下:

module.exports = {
  env: {
    browser: true,
    es6: true,
  },
  extends: [
    'airbnb-base',
  ],
  globals: {
    Atomics: 'readonly',
    SharedArrayBuffer: 'readonly',
  },
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module',
  },
  rules: {
  },
};

我们在该配置文件中可以修改验证规则,具体的内容同样参考上面给出的链接。

4、在当前目录下,创建一个js文件

// index.js
var unused = '灰与幻想的格林姆迦尔';

function hello(){
    var message = "Hello, zhaoyi!";
    alert(message);
}
  
hello(); 

5、通过eslint验证代码编写正确性

$ eslint index.js

 1:12  error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  2:1   error    Unexpected var, use let or const instead         no-var
  2:5   error    'unused' is assigned a value but never used      no-unused-vars
  2:27  error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  3:1   error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  4:17  error    Missing space before opening brace               space-before-blocks
  4:18  error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  5:1   error    Expected indentation of 2 spaces but found 4     indent
  5:5   error    Unexpected var, use let or const instead         no-var
  5:19  error    Strings must use singlequote                     quotes
  5:36  error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  6:1   error    Expected indentation of 2 spaces but found 4     indent
  6:5   warning  Unexpected alert                                 no-alert
  6:20  error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  7:2   error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  8:1   error    Trailing spaces not allowed                      no-trailing-spaces
  8:3   error    Expected linebreaks to be 'LF' but found 'CRLF'  linebreak-style
  9:9   error    Trailing spaces not allowed                      no-trailing-spaces
  9:10  error    Newline required at end of file but not found    eol-last

其中,有一种错误其实是因为git文件格式转化的问题:

... linebreak-style

我们可以在配置文件中移除该检测:在rules下添加’linebreak-style’: [0, ‘error’, ‘windows’].

rules: {
    'linebreak-style': [0, 'error', 'windows']
  }

继续运行检测命令,可以看到如下的输出:

  2:1   error    Unexpected var, use let or const instead      no-var
  2:5   error    'unused' is assigned a value but never used   no-unused-vars
  5:1   error    Expected indentation of 2 spaces but found 4  indent
  5:5   error    Unexpected var, use let or const instead      no-var
  5:19  error    Strings must use singlequote                  quotes
  6:1   error    Expected indentation of 2 spaces but found 4  indent
  6:5   warning  Unexpected alert                              no-alert
  8:1   error    Trailing spaces not allowed                   no-trailing-spaces
  9:9   error    Trailing spaces not allowed                   no-trailing-spaces

可以看到,我们许多不规范的操作都会警告了。比如缩进不要用四空格(其实是我们的编译器自带,而且我们习惯了的),不要加多余的空格,以及删掉没有使用过的声明变量,不推荐使用var类型等等。

如果觉得合情合理,那么遵循之;如果觉得缩进这些不符合自己的习惯,也可以通过配置文件进行关闭/修改等操作达到预期的效果。

 

海计划公众号
(0)
上一篇 2020/03/23 08:58
下一篇 2020/03/23 08:58

您可能感兴趣的内容