詳解JS ES6編碼規(guī)范
1、塊級(jí)作用域
1.1、let取代var
ES6 提出了兩個(gè)新的聲明變量的命令: let 和const。其中,let可以完全取代var,因?yàn)閮烧哒Z義相同,而且let沒有副作用。
var命令存在變量提升的特性,而let沒有這個(gè)命令。
所謂變量提升,即指變量可以先使用,再聲明,顯然,這種編碼規(guī)范非常不適合閱讀。
1.2、全局常量和線程安全
在let和const之間,優(yōu)先使用const。
let應(yīng)出現(xiàn)在單線程模塊代碼內(nèi),而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、字符串
靜態(tài)字符串一律使用單引號(hào)或者反引號(hào),不推薦使用雙引號(hào)。
動(dòng)態(tài)字符串(字符串模板)使用反引號(hào)。
// 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、解構(gòu)賦值
1、使用數(shù)組成員對(duì)變量進(jìn)行賦值時(shí),優(yōu)先使用解構(gòu)賦值。
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、函數(shù)的參數(shù)如果是對(duì)象的成員,優(yōu)先使用解構(gòu)賦值。
// 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、如果函數(shù)返回多個(gè)值,優(yōu)先使用對(duì)象的結(jié)構(gòu)賦值,而不是數(shù)組的結(jié)構(gòu)賦值。這樣便于以后添加返回值,以及更改返回值的順序。
// bad
function getInfo(input){
return [left, right];
}
// good
function getInfo2(input){
return {left, right};
}
// 此處使用對(duì)象的解構(gòu)賦值方式接收返回結(jié)果
const {left, right} = getInfo2('test');
4、對(duì)象
1、單行定義的對(duì)象,最后一個(gè)成員不以逗號(hào)結(jié)尾。多行定義的對(duì)象,最后一個(gè)成員以逗號(hào)結(jié)尾。
// 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、對(duì)象盡量靜態(tài)化,一旦定義,就不得隨意添加新的屬性。如果添加屬性不可避免,要使用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、如果對(duì)象的屬性名是動(dòng)態(tài)的(所謂動(dòng)態(tài)是指,需要通過計(jì)算得到),可以在創(chuàng)建對(duì)象的時(shí)候使用屬性表達(dá)式定義。(此種情況在開發(fā)時(shí),并不多見。)
5、數(shù)組
使用擴(kuò)展運(yùn)算符(...)復(fù)制數(shù)組。
// 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 方法將類似數(shù)組的對(duì)象轉(zhuǎn)為數(shù)組。
const obj = { "0": "a", "1": "b", length: 2};
const arr = Array.from(obj);
// test
console.log(arr); // ["a", "b"]
6、函數(shù)
1、立即執(zhí)行函數(shù)可以寫成箭頭函數(shù)的形式。
(() => {
console.log('this is a good night.');
})();
2、在需要使用函數(shù)表達(dá)式的場合,盡量用箭頭函數(shù)代替。因?yàn)檫@樣可以更簡潔,而且綁定了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、箭頭函數(shù)取代Function.prototype.bind,不應(yīng)再用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、單行簡單、無需復(fù)用的函數(shù),建議采用箭頭函數(shù)。如果函數(shù)體較為復(fù)雜,行數(shù)較多,還是應(yīng)采用傳統(tǒng)的函數(shù)寫法。
5、所有配置項(xiàng)都應(yīng)該集中在一個(gè)對(duì)象,放在到最后一個(gè)參數(shù),布爾值不可以直接作為參數(shù)。
// bad
function divide(a, b, option = false){
}
// good
function divide(a, b, {option = false} = {}){
}
6、不要在函數(shù)體內(nèi)使用arguments變量,使用rest運(yùn)算符(...)代替。因?yàn)閞est運(yùn)算符可以顯示聲明我們想要獲取的參數(shù),而且arguments是一個(gè)類似數(shù)組的對(duì)象,而rest元素安撫可以提供一個(gè)真正的數(shù)組。
// 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
擴(kuò)展運(yùn)算符用三個(gè)點(diǎn)號(hào)表示,功能是把數(shù)組或類數(shù)組對(duì)象展開成一系列用逗號(hào)隔開的值;而rest運(yùn)算符也是三個(gè)點(diǎn)號(hào),不過其功能與擴(kuò)展運(yùn)算符恰好相反,把逗號(hào)隔開的值序列組合成一個(gè)數(shù)組。rest是剩余的意思。
7、使用默認(rèn)值語法設(shè)置函數(shù)參數(shù)的默認(rèn)值。
// bad
function handleThings(opts){
opts = opts || {};
// ...
}
// good
function handleThings2(opts = {}){
// ...
}
7、Map結(jié)構(gòu)
Map和Object給人的感覺是同一個(gè)數(shù)據(jù)類型,但是在實(shí)際語義還需要更為準(zhǔn)確的區(qū)分,原則如下:
- 模擬實(shí)體對(duì)象時(shí),使用Object;
- 只需要k-v鍵值對(duì)數(shù)據(jù)結(jié)構(gòu)時(shí),使用Map;
Map擁有內(nèi)建的遍歷機(jī)制(實(shí)現(xiàn)了Iterator結(jié)構(gòu))
// Map擁有許多初始化方式,這里使用數(shù)組成員為兩個(gè)長度的數(shù)組進(jìn)行初始化(第一個(gè)元素為K,第二個(gè)元素為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的操作。因?yàn)镃lass的寫法更簡潔,更易于理解。接觸過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的朋友想必知道一個(gè)規(guī)則:
// 那就是在設(shè)計(jì)構(gòu)造函數(shù)時(shí),若傳入的參數(shù)中有可變類型(對(duì)象、數(shù)組),
// 則構(gòu)造函數(shù)內(nèi)部接收此參數(shù)時(shí)應(yīng)使用這個(gè)對(duì)象的拷貝。
// 這樣可以避免外部參數(shù)對(duì)象的更改影響到類本身的實(shí)例。
// 因此,此處的contents需要拷貝一個(gè)復(fù)制在進(jìn)行賦值。
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實(shí)現(xiàn)繼承,因?yàn)檫@樣可以更簡單,不存在破壞instanceof運(yùn)算的危險(xiǎn)。
// Queue為上一個(gè)例子的類
class PeekQueue extends Queue{
// ...
}
9、模塊
1、Module語法是js模塊的標(biāo)準(zhǔn)寫法,要堅(jiān)持使用這種寫法。使用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、如果模塊只有一個(gè)輸出值,就使用 export default; 若有鍍鉻,就不要使用 export default, 不要同時(shí)使用 export default 和 普通的 export,雖然規(guī)則上允許此種編寫代碼的方式。
4、不要在模塊中使用通配符,因?yàn)檫@樣可以確保模塊中有一個(gè)默認(rèn)輸出:export default。
// bad import * as myObject './someModule'; // good import myObject from './someModule';
5、如果模塊默認(rèn)輸出一個(gè)函數(shù),函數(shù)的首字母應(yīng)該小寫。
function someFunction(){
// ...
}
export default someFunction;
6、 如果模塊默認(rèn)輸出一個(gè)對(duì)象,對(duì)象名的首字母應(yīng)該大寫。
const someObj = {
// ...
}
export default SomeObj;
10、ESLint
前面說了那么多規(guī)則,其實(shí)只是規(guī)則范本的冰山一角,真正想要寫出格式優(yōu)美、符合主流廠商規(guī)范的代碼,僅僅靠我們的自覺是不夠的。
有沒有什么類似軟件編譯工具檢查代碼正確性來檢查代碼編寫規(guī)范的軟件呢,答案是有的。
ESLint就是這樣的一款檢查工具。可以用于保證寫出語法正確、風(fēng)格統(tǒng)一的代碼。
以下是安裝ESLink的教程(確保您的環(huán)境已經(jīng)安裝了npm),當(dāng)然,如果您使用一些腳手架工具(例如@vue-cli)等方式生成的項(xiàng)目,那么這樣的項(xiàng)目都是提供了可選的eslint插件的。當(dāng)前版本為: v6.6.0。該版本的eslint提供了更為簡單的配置方式,可以參考https://eslint.bootcss.com/docs/user-guide/getting-started/進(jìn)行配置。以下是一個(gè)粗略的配置步驟
1、安裝所需插件
$ npm install eslint -g
2、生成package.json文件
$ npm init
該方法會(huì)在當(dāng)前目錄生成package.json文件,該文件類似于環(huán)境的說明文件。
3、生成eslint配置文件
$ eslint --init
該命令會(huì)詢問你使用哪種類型的配置(通過上下箭頭選?。?/p>
- 推薦選用json或者JavaScript類型,我這里使用的是JavaScript類型的配置文件
- style guide選用airbnb。
其他的選項(xiàng)根據(jù)你的需要進(jìn)行選取即可。完成選擇之后,會(huì)自動(dòng)下載所需要的依賴包。
生成的配置文件內(nèi)容大致如下:
module.exports = {
env: {
browser: true,
es6: true,
},
extends: [
'airbnb-base',
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
rules: {
},
};
我們?cè)谠撆渲梦募锌梢孕薷尿?yàn)證規(guī)則,具體的內(nèi)容同樣參考上面給出的鏈接。
4、在當(dāng)前目錄下,創(chuàng)建一個(gè)js文件
// index.js
var unused = '灰與幻想的格林姆迦爾';
function hello(){
var message = "Hello, zhaoyi!";
alert(message);
}
hello();
5、通過eslint驗(yàn)證代碼編寫正確性
$ 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
其中,有一種錯(cuò)誤其實(shí)是因?yàn)間it文件格式轉(zhuǎn)化的問題:
... linebreak-style
我們可以在配置文件中移除該檢測(cè):在rules下添加'linebreak-style': [0, 'error', 'windows'].
rules: {
'linebreak-style': [0, 'error', 'windows']
}
繼續(xù)運(yùn)行檢測(cè)命令,可以看到如下的輸出:
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
可以看到,我們?cè)S多不規(guī)范的操作都會(huì)警告了。比如縮進(jìn)不要用四空格(其實(shí)是我們的編譯器自帶,而且我們習(xí)慣了的),不要加多余的空格,以及刪掉沒有使用過的聲明變量,不推薦使用var類型等等。
如果覺得合情合理,那么遵循之;如果覺得縮進(jìn)這些不符合自己的習(xí)慣,也可以通過配置文件進(jìn)行關(guān)閉/修改等操作達(dá)到預(yù)期的效果。
以上就是詳解JS ES6編碼規(guī)范的詳細(xì)內(nèi)容,更多關(guān)于JS ES6編碼規(guī)范的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JavaScript實(shí)現(xiàn)excel文件導(dǎo)入導(dǎo)出
這篇文章主要介紹了JavaScript實(shí)現(xiàn)excel文件導(dǎo)入導(dǎo)出,文件的導(dǎo)入導(dǎo)出是非常常見的需求功能,excel文件的導(dǎo)入導(dǎo)出更為常見,實(shí)踐中許多時(shí)候,是調(diào)用接口實(shí)現(xiàn)導(dǎo)入導(dǎo)出的,具體實(shí)現(xiàn)內(nèi)容需要的小伙伴可以參考一下2022-06-06
JavaScript將數(shù)組轉(zhuǎn)換成CSV格式的方法
這篇文章主要介紹了JavaScript將數(shù)組轉(zhuǎn)換成CSV格式的方法,實(shí)例分析了javascript使用valueOf方法將數(shù)組值轉(zhuǎn)換為csv格式字符串的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03
Web開發(fā)中客戶端的跳轉(zhuǎn)與服務(wù)器端的跳轉(zhuǎn)的區(qū)別
這篇文章主要介紹了Web開發(fā)中客戶端的跳轉(zhuǎn)與服務(wù)器端的跳轉(zhuǎn)的區(qū)別 ,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-03-03
JavaScript字符串轉(zhuǎn)換數(shù)字的方法
這篇文章主要介紹了JavaScript字符串轉(zhuǎn)換數(shù)字的方法,文章圍繞JavaScript字符串轉(zhuǎn)換數(shù)字的相關(guān)資料展開全文內(nèi)容,需要的小伙伴可以參考一下2021-12-12
JavaScript通過元素索引號(hào)刪除數(shù)組中對(duì)應(yīng)元素的方法
這篇文章主要介紹了JavaScript通過元素索引號(hào)刪除數(shù)組中對(duì)應(yīng)元素的方法,涉及javascript操作數(shù)組的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03
IE中JS跳轉(zhuǎn)丟失referrer問題的2個(gè)解決方法
這篇文章主要介紹了IE中JS跳轉(zhuǎn)丟失referrer問題的2個(gè)解決方法,算是IE的一個(gè)BUG吧,本文提供了2個(gè)方法解決這個(gè)問題,需要的朋友可以參考下2014-07-07

