详解JS ES6编码规范

 更新时间:2021年5月8日 10:00  点击:2611

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

扩展运算符用三个点号表示,功能是把数组或类数组对象展开成一系列用逗号隔开的值;而rest运算符也是三个点号,不过其功能与扩展运算符恰好相反,把逗号隔开的值序列组合成一个数组。rest是剩余的意思。

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类型等等。

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

以上就是详解JS ES6编码规范的详细内容,更多关于JS ES6编码规范的资料请关注猪先飞其它相关文章!

[!--infotagslink--]

相关文章

  • js实现浏览器打印功能的示例代码

    这篇文章主要介绍了js如何实现浏览器打印功能,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下...2020-07-15
  • JavaScript判断浏览器及其版本信息

    本篇文章主要分享了通过window.navigator来判断浏览器及其版本信息的实例代码。具有一定的参考价值,下面跟着小编一起来看下吧...2017-01-23
  • Nest.js参数校验和自定义返回数据格式详解

    这篇文章主要给大家介绍了关于Nest.js参数校验和自定义返回数据格式的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-28
  • js实现调用网络摄像头及常见错误处理

    这篇文章主要介绍了js实现调用网络摄像头及常见错误处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-07
  • JS实现随机生成验证码

    这篇文章主要为大家详细介绍了JS实现随机生成验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-06
  • JS实现响应鼠标点击动画渐变弹出层效果代码

    这篇文章主要介绍了JS实现响应鼠标点击动画渐变弹出层效果代码,具有非常自然流畅的动画过度效果,涉及JavaScript针对鼠标事件的响应及页面元素样式的动态操作相关技巧,需要的朋友可以参考下...2016-03-28
  • 基于JavaScript实现文字超出部分隐藏

    这篇文章主要介绍了基于JavaScript实现文字超出部分隐藏 的相关资料,需要的朋友可以参考下...2016-03-01
  • NodeJS实现阿里大鱼短信通知发送

    本文给大家介绍的是nodejs实现使用阿里大鱼短信API发送消息的方法和代码,有需要的小伙伴可以参考下。...2016-01-20
  • 浅析AngularJS Filter用法

    系统的学习了一下angularjs,发现angularjs的有些思想根php的模块smarty很像,例如数据绑定,filter。如果对smarty比较熟悉的话,学习angularjs会比较容易一点,这篇文章给大家介绍angularjs filter用法详解,感兴趣的朋友一起学习吧...2015-12-29
  • js实现列表按字母排序

    这篇文章主要为大家详细介绍了js实现列表按字母排序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-08-11
  • NODE.JS加密模块CRYPTO常用方法介绍

    使用require('crypto')调用加密模块。加密模块需要底层系统提供OpenSSL的支持。它提供了一种安全凭证的封装方式,可以用于HTTPS安全网络以及普通HTTP连接。该模块还提供了一套针对OpenSSL的hash(哈希),hmac(密钥哈希),cipher...2014-06-07
  • node.JS md5加密中文与php结果不一致怎么办

    这次文章要给大家介绍的是node.JS md5加密中文与php结果不一致怎么办,不知道具体解决办法的下面跟小编一起来看看。 因项目需要,需要Node.js与PHP做接口调用,发现nod...2017-07-06
  • Bootstrap3制作图片轮播效果

    这篇文章主要教大家如何利用Bootstrap3制作图片轮播效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2016-05-14
  • Bootstrap教程JS插件滚动监听学习笔记分享

    这篇文章主要为大家分享了Bootstrap教程JS插件滚动监听学习笔记,内容很详细,感兴趣的小伙伴们可以参考一下...2016-05-20
  • JS实现纸牌发牌动画

    这篇文章主要为大家详细介绍了JS实现纸牌发牌动画,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-01-19
  • 基于JavaScript实现表单密码的隐藏和显示出来

    为了网站的安全性,很多朋友都把密码设的比较复杂,但是如何密码不能明显示,不知道输的是对是错,为了安全起见可以把密码显示的,那么基于js代码如何实现的呢?下面通过本文给大家介绍JavaScript实现表单密码的隐藏和显示,需要的朋友参考下...2016-03-03
  • Nodejs中使用captchapng模块生成图片验证码

    本篇文章主要介绍了Nodejs中使用captchapng模块实现图片验证码,非常具有实用价值,需要的朋友可以参考下 ...2017-05-22
  • AngularJS 实现按需异步加载实例代码

    AngularJS 通过路由支持多视图应用, 可以根据路由动态加载所需的视图, 在 AngularJS 的文档中有详细的介绍, 网上也有不少教程, 就不用介绍了!随着视图的不断增加,js文件会越来越多,而 AngularJS 默认需要把全部的js都一次性...2015-10-21
  • 安装使用Mongoose配合Node.js操作MongoDB的基础教程

    这篇文章主要介绍了安装使用Mongoose来让Node.js操作MongoDB的基础教程,前端js+后端node+js操作MongoDB正是所谓最流行的一种JavaScript全栈开发方案,需要的朋友可以参考下...2016-03-03
  • JS实现仿百度文库评分功能

    本文给大家分享基于js实现仿百度文库评分功能,代码简单易懂,非常不错,具有参考借鉴价值,需要的的朋友参考下吧...2017-01-16