详解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 面向对象(一)(共有方法,私有方法,特权方法)
May 23 Javascript
js判断FCKeditor内容是否为空的两种形式
May 14 Javascript
jQuery动画效果-slideUp slideDown上下滑动示例代码
Aug 28 Javascript
js采用concat和sort将N个数组拼接起来的方法
Jan 21 Javascript
javascript解决小数的加减乘除精度丢失的方案
May 31 Javascript
前端面试知识点锦集(JavaScript篇)
Dec 28 Javascript
几种tab切换详解
Feb 03 Javascript
JS实现颜色的10进制转化成rgba格式的方法
Sep 04 Javascript
微信小程序页面间传值与页面取值操作实例分析
Apr 30 Javascript
js 将线性数据转为树形的示例代码
May 28 Javascript
node.js中path路径模块的使用方法实例分析
Feb 13 Javascript
vue+ESLint 配置保存 自动格式化代码
Mar 17 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 图片文件上传实现代码
2010/12/29 PHP
php递归创建目录的方法
2015/02/02 PHP
PHP.ini安全配置检测工具pcc简单介绍
2015/07/02 PHP
thinkphp跨库操作的简单代码实例
2016/09/22 PHP
JS查看对象功能代码
2008/04/25 Javascript
基于JQuery 选择器使用说明介绍
2013/04/18 Javascript
js中function()使用方法
2013/12/24 Javascript
使用POST方式弹出窗口的两种方法示例介绍
2014/01/29 Javascript
js和jquery中循环的退出和继续学习记录
2014/09/06 Javascript
javascript常用的方法分享
2015/07/01 Javascript
javascript产生随机数方法汇总
2016/01/25 Javascript
详解使用Vue.Js结合Jquery Ajax加载数据的两种方式
2017/01/10 Javascript
jQuery中ztree 点击文本框弹出下拉框的实例代码
2017/02/05 Javascript
nodejs 如何手动实现服务器
2018/08/20 NodeJs
利用chrome浏览器进行js调试并找出元素绑定的点击事件详解
2021/01/30 Javascript
微信小程序功能之全屏滚动效果的实现代码
2018/11/22 Javascript
vue实现图书管理系统
2020/12/29 Vue.js
Python实现遍历数据库并获取key的值
2015/05/17 Python
在Python中操作字符串之replace()方法的使用
2015/05/19 Python
Python使用matplotlib绘制动画的方法
2015/05/20 Python
Python中矩阵库Numpy基本操作详解
2017/11/21 Python
TENSORFLOW变量作用域(VARIABLE SCOPE)
2020/01/10 Python
基于python实现检索标记敏感词并输出
2020/05/07 Python
英国的领先快速时尚零售商:In The Style
2019/03/25 全球购物
介绍一下.net和Java的特点和区别
2012/09/26 面试题
社区工作者先进事迹
2014/01/18 职场文书
商场活动策划方案
2014/01/24 职场文书
业绩考核岗位职责
2014/02/01 职场文书
《猴子种树》教学反思
2014/02/14 职场文书
班主任新年寄语
2014/04/04 职场文书
城管大队整治方案
2014/05/06 职场文书
团支部推优材料
2014/05/21 职场文书
公司财务部岗位职责
2015/04/14 职场文书
2015中学政教处工作总结
2015/07/22 职场文书
2016应届毕业生自荐信范文
2016/01/28 职场文书
2019奶茶店创业计划书范本,值得你借鉴
2019/08/14 职场文书