详解JS ES6编码规范


Posted in Javascript onMay 07, 2021

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编码规范的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
$()JS小技巧
Jul 21 Javascript
JavaScript 解析Json字符串的性能比较分析代码
Dec 16 Javascript
JavaScript 面向对象编程(2) 定义类
May 18 Javascript
jQuery实现仿QQ在线客服效果的滚动层代码
Oct 15 Javascript
jQuery中使用animate自定义动画的方法
May 29 Javascript
jQuery查看选中对象HTML代码的方法
Jun 17 Javascript
jQuery实现 上升、下降、删除、添加一行代码
Mar 06 Javascript
使用nvm管理不同版本的node与npm的方法
Oct 31 Javascript
微信小程序页面调用自定义组件内的事件详解
Sep 12 Javascript
JS实现表单中点击小眼睛显示隐藏密码框中的密码
Apr 13 Javascript
Bootstrap table 服务器端分页功能实现方法示例
Jun 01 Javascript
JS轮播图的实现方法2
Aug 25 Javascript
html5中sharedWorker实现多页面通信的示例代码
May 07 #Javascript
详解如何使用Node.js实现热重载页面
May 06 #Javascript
关于Vue Router的10条高级技巧总结
May 06 #Vue.js
在JavaScript中如何使用宏详解
May 06 #Javascript
如何用JS实现简单的数据监听
May 06 #Javascript
详解TS数字分隔符和更严格的类属性检查
May 06 #Javascript
JS中一些高效的魔法运算符总结
May 06 #Javascript
You might like
PHP和XSS跨站攻击的防范
2007/04/17 PHP
基于PHP+jQuery+MySql实现红蓝(顶踩)投票代码
2015/08/25 PHP
Laravel框架实现定时Task Scheduling例子
2019/10/22 PHP
用循环或if语句从json中取数据示例
2014/08/18 Javascript
js监听鼠标点击和键盘点击事件并自动跳转页面
2014/09/24 Javascript
详谈JavaScript 匿名函数及闭包
2014/11/14 Javascript
使用jQuery实现更改默认alert框体
2015/04/13 Javascript
nodejs实现HTTPS发起POST请求
2015/04/23 NodeJs
JS中使用apply、bind实现为函数或者类传入动态个数的参数
2016/04/26 Javascript
JavaScript_object基础入门(必看篇)
2016/06/13 Javascript
jQuery实现产品对比功能附源码下载
2016/08/09 Javascript
使用bootstrap实现多窗口和拖动效果
2016/09/22 Javascript
easyui-combobox 实现简单的自动补全功能示例
2016/11/08 Javascript
浅谈Vue2.0中v-for迭代语法的变化(key、index)
2018/03/06 Javascript
vue升级之路之vue-router的使用教程
2018/08/14 Javascript
js 使用ajax设置和获取自定义header信息的方法小结
2020/03/12 Javascript
详解vue 组件注册
2020/11/20 Vue.js
使用Python获取CPU、内存和硬盘等windowns系统信息的2个例子
2014/04/15 Python
python获得linux下所有挂载点(mount points)的方法
2015/04/29 Python
Python中死锁的形成示例及死锁情况的防止
2016/06/14 Python
python中使用正则表达式的连接符示例代码
2017/10/10 Python
用python实现百度翻译的示例代码
2018/03/09 Python
python学生管理系统代码实现
2020/04/05 Python
详解python中的json和字典dict
2018/06/22 Python
Gauss-Seidel迭代算法的Python实现详解
2019/06/29 Python
Python3使用 GitLab API 进行批量合并分支
2020/10/15 Python
Html5页面在微信端的分享的实现方法
2018/08/30 HTML / CSS
副董事长岗位职责
2014/04/02 职场文书
网页美工求职信范文
2014/04/17 职场文书
优秀语文教师事迹
2014/05/18 职场文书
小学捐书活动总结
2014/07/05 职场文书
2015年乡镇流动人口工作总结
2015/05/12 职场文书
2015年敬老院工作总结
2015/05/18 职场文书
幼儿园教师管理制度
2015/08/05 职场文书
Spring Data JPA的Audit功能审计数据库的变更
2021/06/26 Java/Android
MySQL数据库10秒内插入百万条数据的实现
2021/11/01 MySQL