详解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 相关文章推荐
JavaScript中String和StringBuffer的速度之争
Apr 01 Javascript
JS图片根据鼠标滚动延时加载的实例代码
Jul 13 Javascript
javascript在网页中实现读取剪贴板粘贴截图功能
Jun 07 Javascript
jQuery源码分析之jQuery.fn.each与jQuery.each用法
Jan 23 Javascript
Vue.js每天必学之计算属性computed与$watch
Sep 05 Javascript
js学习总结之dom2级事件基础知识详解
Jul 27 Javascript
JavaScript数据类型的存储方法详解
Aug 25 Javascript
react 实现页面代码分割、按需加载的方法
Apr 03 Javascript
关于js的三种使用方式(行内js、内部js、外部js)的程序代码
May 05 Javascript
vue项目环境变量配置的实现方法
Oct 12 Javascript
vue工程全局设置ajax的等待动效的方法
Feb 22 Javascript
vue 内联样式style中的background用法说明
Aug 05 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处理图片变得简单 基于gb库的图片处理类附实例代码下载
2011/05/17 PHP
php处理restful请求的路由类分享
2014/02/27 PHP
PHP的时间戳与具体时间转化的简单实现
2016/06/13 PHP
php生成二维码图片方法汇总
2016/12/17 PHP
PHP的new static和new self的区别与使用
2019/11/27 PHP
基于jQuery的js分页代码
2010/06/10 Javascript
JS获取DropDownList的value值与text值的示例代码
2014/01/07 Javascript
js判断浏览器是否支持html5
2014/08/17 Javascript
javascript控制层显示或隐藏的方法
2015/07/22 Javascript
谈谈Jquery ajax中success和complete有哪些不同点
2015/11/20 Javascript
jQuery动画效果相关方法实例分析
2015/12/31 Javascript
JavaScript中全选、全不选、反选、无刷新删除、批量删除、即点即改入库(在yii框架中操作)的代码分享
2016/11/01 Javascript
vuejs绑定class和style样式
2017/04/11 Javascript
前端构建工具之gulp的配置与搭建详解
2017/06/12 Javascript
清空元素html(&quot;&quot;) innerHTML=&quot;&quot; 与 empty()的区别和应用(推荐)
2017/08/14 Javascript
浅谈Webpack 持久化缓存实践
2018/03/22 Javascript
详解用Webpack与Babel配置ES6开发环境
2019/03/12 Javascript
微信小程序搭建自己的Https服务器
2019/05/02 Javascript
微信小程序合法域名配置方法
2019/05/06 Javascript
JQuery实现ul中添加LI和删除指定的Li元素功能完整示例
2019/10/16 jQuery
js实现鼠标点击页面弹出自定义文字效果
2019/12/24 Javascript
Python实现命令行通讯录实例教程
2016/08/18 Python
python实现随机梯度下降法
2020/03/24 Python
Python任意字符串转16, 32, 64进制的方法
2019/06/12 Python
安装好Pycharm后如何配置Python解释器简易教程
2019/06/28 Python
windows下python虚拟环境virtualenv安装和使用详解
2019/07/16 Python
在python3中使用shuffle函数要注意的地方
2020/02/28 Python
python pandas利用fillna方法实现部分自动填充功能
2020/03/16 Python
Django contrib auth authenticate函数源码解析
2020/11/12 Python
香港化妆品经销商:我的公主
2016/08/05 全球购物
adidas官方旗舰店:德国运动用品制造商
2017/11/25 全球购物
群胜软件Java笔试题
2012/09/29 面试题
C#笔试题和英文面试题
2013/02/07 面试题
公司中层干部的自我评价分享
2014/03/01 职场文书
2014年公司工作总结
2014/11/22 职场文书
js前端设计模式优化50%表单校验代码示例
2022/06/21 Javascript