javascript
Airbnb JavaScript 编码风格指南(2018年最新版)
Airbnb JavaScript 編碼風(fēng)格指南(2018年最新版)
訪問(wèn)此原文地址:http://galaxyteam.pub/didi-fe...另外歡迎訪問(wèn)我們維護(hù)的https://www.threejs.online 中文站 (歡迎Star!)
本文譯者:滴滴出行上海前端(FE)團(tuán)隊(duì)楊永樂(lè)同學(xué)
類型
基本類型:直接存取
- string
- number
- boolean
- null
- undefined
- symbol
- symbol 類型不能完全polyfilled,所以請(qǐng)謹(jǐn)慎使用
復(fù)雜類型: 通過(guò)引用的方式存取
- object
- array
- function
引用
使用const申明引用類型,避免使用var。eslint 設(shè)置:prefer-const,no-const-assign
為什么?這能確保你無(wú)法對(duì)引用重新賦值,也不會(huì)導(dǎo)致出現(xiàn) bug 或難以理解。 // bad var a = 1; var b = 2;// good const a = 1; const b = 2;如果必須對(duì)引用類型重新賦值,使用let而非var。eslint設(shè)置:no-var jscs: disallowVar
為什么?相比于var函數(shù)作用域,let塊級(jí)作用域更容易理解 // bad var count = 1; if (true) {count += 1; }// good, use the let. let count = 1; if (true) {count += 1; }注意let和const都是塊級(jí)作用域
// const and let only exist in the blocks they are defined in. {let a = 1;const b = 1; } console.log(a); // ReferenceError console.log(b); // ReferenceError對(duì)象
使用字面值創(chuàng)建對(duì)象。eslint: no-new-object
// bad const item = new Object();// good const item = {};創(chuàng)建對(duì)象的動(dòng)態(tài)屬性時(shí),使用計(jì)算屬性
為什么?這樣可以在一個(gè)地方定義對(duì)象所有的屬性 function getKey(k) {return `a key named ${k}`; }// bad const obj = {id: 5,name: 'San Francisco', }; obj[getKey('enabled')] = true;// good const obj = {id: 5,使用對(duì)象方法的簡(jiǎn)寫形式。 eslint: object-shorthand jscs: requireEnhancedObjectLiterals
為什么?方法定義簡(jiǎn)潔清晰 // bad const atom = {value: 1,addValue: function (value) {return atom.value + value;}, };// good const atom = {value: 1,addValue(value) {return atom.value + value;}, };使用屬性值簡(jiǎn)寫形式。eslint: object-shorthand jscs: [requireEnhancedObjectLiterals]
為什么?書寫更加簡(jiǎn)潔,更有描述性。 const lukeSkywalker = 'Luke Skywalker';// bad const obj = {lukeSkywalker: lukeSkywalker, };// good const obj = {lukeSkywalker, };對(duì)象聲明時(shí)分類簡(jiǎn)寫和非簡(jiǎn)寫的屬性名。
為什么?更清晰的了解哪些屬性是簡(jiǎn)寫的。 const anakinSkywalker = 'Anakin Skywalker'; const lukeSkywalker = 'Luke Skywalker';// bad const obj = {episodeOne: 1,twoJediWalkIntoACantina: 2,lukeSkywalker,episodeThree: 3,mayTheFourth: 4,anakinSkywalker, };// good const obj = {lukeSkywalker,anakinSkywalker,episodeOne: 1,twoJediWalkIntoACantina: 2,episodeThree: 3,mayTheFourth: 4, };只有對(duì)那些不合法的屬性名標(biāo)識(shí)符添加引號(hào)。eslint: quote-props jscs: disallowQuotedKeysInObjects
為什么?對(duì)象屬性更直觀,可讀性強(qiáng)。能夠代碼高亮顯示,同時(shí)對(duì)于大多數(shù)的js引擎更容易優(yōu)化代碼。 // bad const bad = {'foo': 3,'bar': 4,'data-blah': 5, };// good const good = {foo: 3,bar: 4,'data-blah': 5, };不要直接使用Object.prototype上的方法,例如hasOwnProperty, propertyIsEnumerable, 和 isPrototypeOf。
為什么?這些方法可能受對(duì)象的其他屬性影響。例如{ hasOwnProperty: false } 或者 對(duì)象可能是null(Object.create(null)) // bad console.log(object.hasOwnProperty(key));const object = Object.create(null); obj.hasOwnProperty(key) // Uncaught TypeError: obj.hasOwnProperty is not a function// good console.log(Object.prototype.hasOwnProperty.call(object, key));// best const has = Object.prototype.hasOwnProperty; // cache the lookup once, in module scope. /* or */ import has from 'has'; // https://www.npmjs.com/package/has // ... console.log(has.call(object, key));淺拷貝對(duì)象時(shí)推薦使用對(duì)象展開(kāi)操作(object spread operator)而不是Object.assign。使用對(duì)象剩余操作符(object rest operator)獲取對(duì)象中剩余的屬性。
為什么?Object.assign使用不當(dāng)會(huì)修改原對(duì)象 // very bad const original = { a: 1, b: 2 }; const copy = Object.assign(original, { c: 3 }); // this mutates `original` ?_? delete copy.a; // so does this// bad const original = { a: 1, b: 2 }; const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 }// good const original = { a: 1, b: 2 }; const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 }const { a, ...noA } = copy; // noA => { b: 2, c: 3 }數(shù)組
使用字面量聲明數(shù)組。eslint: no-array-constructor
// bad const items = new Array();// good const items = [];向數(shù)組添加元素時(shí),使用Arrary#push替代直接賦值。
const someStack = [];// bad someStack[someStack.length] = 'abracadabra';// good someStack.push('abracadabra');使用數(shù)組展開(kāi)操作符...拷貝數(shù)組
// bad const len = items.length; const itemsCopy = []; let i;for (i = 0; i < len; i += 1) {itemsCopy[i] = items[i]; }// good const itemsCopy = [...items];將類數(shù)組對(duì)象(array-like)轉(zhuǎn)換成數(shù)組時(shí),使用...而不是Array.from
const foo = document.querySelectorAll('.foo');// good const nodes = Array.from(foo);// best const nodes = [...foo];當(dāng)需要對(duì)可遍歷對(duì)象進(jìn)行map操作時(shí),使用Array.from而不是展開(kāi)操作符...,避免新建一個(gè)臨時(shí)數(shù)組。
// bad const baz = [...foo].map(bar);// good const baz = Array.from(foo, bar);數(shù)組方法回調(diào)需要有返回值。如果函數(shù)體比較簡(jiǎn)單,可以直接用表達(dá)式,省略return語(yǔ)句。 eslint: array-callback-return
// good [1, 2, 3].map((x) => {const y = x + 1;return x * y; });// good [1, 2, 3].map(x => x + 1);// bad - no returned value means `memo` becomes undefined after the first iteration [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {const flatten = memo.concat(item);memo[index] = flatten; });// good [[0, 1], [2, 3], [4, 5]].reduce((memo, item, index) => {const flatten = memo.concat(item);memo[index] = flatten;return flatten; });// bad inbox.filter((msg) => {const { subject, author } = msg;if (subject === 'Mockingbird') {return author === 'Harper Lee';} else {return false;} });// good inbox.filter((msg) => {const { subject, author } = msg;if (subject === 'Mockingbird') {return author === 'Harper Lee';}return false; });如果數(shù)組有多行,請(qǐng)?jiān)诖蜷_(kāi)和關(guān)閉數(shù)組括號(hào)之前使用換行符
為什么? 更具有可讀性 // bad const arr = [[0, 1], [2, 3], [4, 5], ];const objectInArray = [{id: 1, }, {id: 2, }];const numberInArray = [1, 2, ];// good const arr = [[0, 1], [2, 3], [4, 5]];const objectInArray = [{id: 1,},{id: 2,}, ];const numberInArray = [1,2, ];解構(gòu)
訪問(wèn)和使用對(duì)象的多個(gè)屬性時(shí)用對(duì)象解構(gòu)操作。eslint: prefer-destructuring jscs: requireObjectDestructuring
為什么?解構(gòu)可以避免為這些屬性創(chuàng)建臨時(shí)引用。 // bad function getFullName(user) {const firstName = user.firstName;const lastName = user.lastName;return `${firstName} ${lastName}`; }// good function getFullName(user) {const { firstName, lastName } = user;return `${firstName} ${lastName}`; }// best function getFullName({ firstName, lastName }) {return `${firstName} ${lastName}`; }使用數(shù)組解構(gòu)。eslint: prefer-destructuring jscs: requireArrayDestructuring
const arr = [1, 2, 3, 4];// bad const first = arr[0]; const second = arr[1];// good const [first, second] = arr;使用對(duì)象解構(gòu)來(lái)實(shí)現(xiàn)多個(gè)返回值,而不是數(shù)組解構(gòu)。jscs: disallowArrayDestructuringReturn
為什么?你可以隨時(shí)為返回值新增屬性而不用關(guān)心屬性的順序。 // bad function processInput(input) {// then a miracle occursreturn [left, right, top, bottom]; }// 調(diào)用者需要注意返回值中對(duì)象的順序 const [left, __, top] = processInput(input);// good function processInput(input) {// then a miracle occursreturn { left, right, top, bottom }; }// 調(diào)用者只需要使用它需要的對(duì)象 const { left, top } = processInput(input);字符串
字符串使用單引號(hào)。eslint: quotes jscs: validateQuoteMarks
// bad const name = "Capt. Janeway";// bad - 當(dāng)需要插值或者換行時(shí)才使用模板文字 const name = `Capt. Janeway`;// good const name = 'Capt. Janeway';不超過(guò)100個(gè)字符的字符串不應(yīng)該使用連接符或者換行書寫。
為什么?換行的字符串不好閱讀,并且不方便搜索代碼。 // bad const errorMessage = 'This is a super long error that was thrown because \ of Batman. When you stop to think about how Batman had anything to do \ with this, you would get nowhere \ fast.';// bad const errorMessage = 'This is a super long error that was thrown because ' +'of Batman. When you stop to think about how Batman had anything to do ' +'with this, you would get nowhere fast.';// good const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';以編程方式構(gòu)建字符串時(shí),使用模板字符串而不是連接符。eslint: prefer-template template-curly-spacing jscs: requireTemplateStrings
為什么?模板字符串更為簡(jiǎn)潔,更具可讀性。 // bad function sayHi(name) {return 'How are you, ' + name + '?'; }// bad function sayHi(name) {return ['How are you, ', name, '?'].join(); }// bad function sayHi(name) {return `How are you, ${ name }?`; }// good function sayHi(name) {return `How are you, ${name}?`; }不要過(guò)多的轉(zhuǎn)義字符串。eslint: no-useless-escape
為什么?反斜杠影響代碼可讀性,只有在必要的時(shí)候才使用。 // bad const foo = '\'this\' \i\s \"quoted\"';// good const foo = '\'this\' is "quoted"'; const foo = `my name is '${name}'`;函數(shù)
使用命名函數(shù)表達(dá)式而不是函數(shù)聲明。eslint: func-style jscs: disallowFunctionDeclarations
為什么?函數(shù)聲明會(huì)被提前。這意味著很可能在函數(shù)定義前引用該函數(shù),但是不會(huì)報(bào)錯(cuò)。這不利于代碼的可讀性和可維護(hù)性。如果你發(fā)現(xiàn)一個(gè)函數(shù)定義的很大很復(fù)雜,以至于妨礙了了解文件中的其他內(nèi)容,那么是時(shí)候把這個(gè)函數(shù)提取到自己的模塊中去了!不要忘記顯示指定表達(dá)式的名稱,盡管它能從變量名中被推斷出來(lái)(現(xiàn)代瀏覽器或者編譯器(如Babel)支持)。這能讓錯(cuò)誤的調(diào)用棧更清晰。(討論) // bad function foo() {// ... }// bad const foo = function () {// ... };// good // 函數(shù)名和變量引用名不同 const short = function longUniqueMoreDescriptiveLexicalFoo() {// ... }; // Is it worse const sum = function(a, b) {return a + b; };// than this? const my_sum = function sum(a, b) {return a + b; }; 第一個(gè)函數(shù)沒(méi)有.name屬性,在debugging過(guò)程中,它會(huì)是一個(gè)匿名函數(shù)。第二個(gè)函數(shù)有名字為sum,你可以檢索到它,調(diào)試過(guò)程中能夠快速定位。使用banel 和babel-preset-env配置,const foo = () => {}會(huì)轉(zhuǎn)換成var foo = function foo () {},并且從Node v6開(kāi)始,const foo = () => {}中的foo 也有.name。所以它不再是匿名函數(shù)。(函數(shù)名字推斷)
用圓括號(hào)包裹立即執(zhí)行函數(shù)表達(dá)式(IIFE)。eslint: wrap-iife jscs: requireParenthesesAroundIIFE
為什么? 立即執(zhí)行函數(shù)表達(dá)式是單一執(zhí)行單元-使用圓括號(hào)包裹調(diào)用,簡(jiǎn)潔明了的表示了這一點(diǎn)。請(qǐng)注意,在通用的模塊中,你幾乎用不到IIFE。 // immediately-invoked function expression (IIFE) (function () {console.log('Welcome to the Internet. Please follow me.'); }());注意:ECMA-262把block定義為一組語(yǔ)句。但是函數(shù)聲明不是語(yǔ)句。
// bad if (currentUser) {function test() {console.log('Nope.');} }// good let test; if (currentUser) {test = () => {console.log('Yup.');}; }永遠(yuǎn)不要把參數(shù)命名為arguments。這將取代原來(lái)函數(shù)作用域內(nèi)的 arguments對(duì)象。
// bad function foo(name, options, arguments) {// ... }// good function foo(name, options, args) {// ... }不要使用arguments。可以選擇 rest 語(yǔ)法 ... 替代。
為什么?使用 ... 能明確你要傳入的參數(shù)。另外 rest 參數(shù)是一個(gè)真正的數(shù)組,而 arguments 是一個(gè)類數(shù)組。 // bad function concatenateAll() {const args = Array.prototype.slice.call(arguments);return args.join(''); }// good function concatenateAll(...args) {return args.join(''); }使用函數(shù)默認(rèn)參數(shù)指定默認(rèn)值,而不是用一個(gè)可變的函數(shù)參數(shù)
// really bad function handleThings(opts) {// 不!我們不應(yīng)該改變函數(shù)參數(shù)// 更糟糕的是: 如果 opts 是 falsy (為''或者是false), 它仍然會(huì)被賦值為對(duì)象,但是這可能會(huì)引發(fā)bugopts = opts || {};// ... }// still bad function handleThings(opts) {if (opts === void 0) {opts = {};}// ... }// good function handleThings(opts = {}) {// ... }8.使用函數(shù)參數(shù)默認(rèn)值的時(shí)避免副作用。
> 為什么?這樣的寫法會(huì)讓人困惑。```javascript var b = 1; // bad function count(a = b++) {console.log(a); } count(); // 1 count(); // 2 count(3); // 3 count(); // 3 ```參數(shù)默認(rèn)值放在函數(shù)參數(shù)列表的最后。
// bad function handleThings(opts = {}, name) {// ... }// good function handleThings(name, opts = {}) {// ... }不要使用Function構(gòu)造器創(chuàng)建函數(shù)。 eslint: no-new-func
為什么?通過(guò)這種方式創(chuàng)建的函數(shù)和使用eval()類似,會(huì)帶來(lái)不確定的問(wèn)題 // bad var add = new Function('a', 'b', 'return a + b');// still bad var subtract = Function('a', 'b', 'return a - b');函數(shù)名兩邊留白。eslint: space-before-function-paren [space-before-blocks]
為什么?保持代碼一致性,當(dāng)你添加或者刪除名字時(shí)不需要額外增減空格。 // bad const f = function(){}; const g = function (){}; const h = function() {};// good const x = function () {}; const y = function a() {};不要修改參數(shù)。 eslint: no-param-reassign
為什么?操作參數(shù)對(duì)象會(huì)在原始調(diào)用方中導(dǎo)致不可預(yù)知的變量副作用。 // bad function f1(obj) {obj.key = 1; }// good function f2(obj) {const key = Object.prototype.hasOwnProperty.call(obj, 'key') ? obj.key : 1; }不要給參數(shù)賦值。eslint: no-param-reassign
為什么?重新分配參數(shù)可能會(huì)導(dǎo)致意外的行為,特別是在訪問(wèn)參數(shù)對(duì)象時(shí)。 它也可能導(dǎo)致優(yōu)化問(wèn)題,特別是在V8中。 // bad function f1(a) {a = 1;// ... }function f2(a) {if (!a) { a = 1; }// ... }// good function f3(a) {const b = a || 1;// ... }function f4(a = 1) {// ... }使用展開(kāi)操作符...調(diào)用可變參數(shù)函數(shù)。eslint: prefer-spread
為什么?它更簡(jiǎn)潔,你不需要提供上下文,并且組合使用new和apply不容易。 // bad const x = [1, 2, 3, 4, 5]; console.log.apply(console, x);// good const x = [1, 2, 3, 4, 5]; console.log(...x);// bad new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5]));// good new Date(...[2016, 8, 5]);帶有多行函數(shù)簽名或調(diào)用的函數(shù)應(yīng)該像本指南中的其他多行列表一樣縮進(jìn):每行中包含一項(xiàng),最后一個(gè)項(xiàng)目帶有逗號(hào)。
// bad function foo(bar,baz,quux) {// ... }// good function foo(bar,baz,quux, ) {// ... }// bad console.log(foo,bar,baz);// good console.log(foo,bar,baz, );箭頭函數(shù)
當(dāng)你必須要使用匿名函數(shù)(如在傳遞內(nèi)聯(lián)回調(diào)時(shí)),請(qǐng)使用箭頭函數(shù)。eslint: prefer-arrow-callback, arrow-spacing jscs: requireArrowFunctions
為什么?因?yàn)榧^函數(shù)創(chuàng)造了新的一個(gè) this 執(zhí)行環(huán)境,通常情況下都能滿足你的需求,而且這樣的寫法更為簡(jiǎn)潔。(參考 Arrow functions - JavaScript | MDN )為什么不?如果你有一個(gè)相當(dāng)復(fù)雜的函數(shù),你或許可以把邏輯部分轉(zhuǎn)移到一個(gè)函數(shù)聲明上。
// bad [1, 2, 3].map(function (x) {const y = x + 1;return x * y; });// good [1, 2, 3].map((x) => {const y = x + 1;return x * y; });如果一個(gè)函數(shù)適合用一行寫出并且只有一個(gè)參數(shù),那就把花括號(hào)、圓括號(hào)和 return 都省略掉。如果不是,那就不要省略。eslint: arrow-parens, arrow-body-style jscs: disallowParenthesesAroundArrowParam, requireShorthandArrowFunctions
為什么?這是一個(gè)很好用的語(yǔ)法糖。在鏈?zhǔn)秸{(diào)用中可讀性很高。 // bad [1, 2, 3].map(number => {const nextNumber = number + 1;`A string containing the ${nextNumber}.`; });// good [1, 2, 3].map(number => `A string containing the ${number}.`);// good [1, 2, 3].map((number) => {const nextNumber = number + 1;return `A string containing the ${nextNumber}.`; });// good如果表達(dá)式過(guò)長(zhǎng)需要多行表示,請(qǐng)將其包含在括號(hào)中,增加可讀性。
為什么?它能清除的標(biāo)識(shí)函數(shù)的開(kāi)始和結(jié)束位置。 // bad ['get', 'post', 'put'].map(httpMethod => Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName,httpMethod,) );// good ['get', 'post', 'put'].map(httpMethod => (Object.prototype.hasOwnProperty.call(httpMagicObjectWithAVeryLongName,httpMethod,) ));如果函數(shù)只有一個(gè)參數(shù)并且函數(shù)體沒(méi)有使用花括號(hào),那就省略括號(hào)。否則,為了保持清晰一致性,總在參數(shù)周圍加上括號(hào)。總是使用括號(hào)也是可以接受的,在這種情況下使用eslint的 “always” option 或者不要在jscs中引入 disallowParenthesesAroundArrowParam。eslint: arrow-parens jscs: disallowParenthesesAroundArrowParam
為什么? 不那么混亂,可讀性強(qiáng)。 // bad [1, 2, 3].map((x) => x * x);// good [1, 2, 3].map(x => x * x);// good [1, 2, 3].map(number => (`A long string with the ${number}. It’s so long that we don’t want it to take up space on the .map line!` ));// bad [1, 2, 3].map(x => {const y = x + 1;return x * y; });// good [1, 2, 3].map((x) => {const y = x + 1;return x * y; });避免箭頭函數(shù)語(yǔ)法(=>)和比較運(yùn)算符(<=,=>)一起使用時(shí)帶來(lái)的困惑。
// bad const itemHeight = item => item.height > 256 ? item.largeSize : item.smallSize;// bad const itemHeight = (item) => item.height > 256 ? item.largeSize : item.smallSize;// good const itemHeight = item => (item.height > 256 ? item.largeSize : item.smallSize);// good const itemHeight = (item) => {const { height, largeSize, smallSize } = item;return height > 256 ? largeSize : smallSize; };類 & 構(gòu)造函數(shù)
總是使用class。避免直接操作prototype。
為什么?class語(yǔ)法更簡(jiǎn)潔更易于理解。 // bad function Queue(contents = []) {this.queue = [...contents]; } Queue.prototype.pop = function () {const value = this.queue[0];this.queue.splice(0, 1);return value; };// good class Queue {constructor(contents = []) {this.queue = [...contents];}pop() {const value = this.queue[0];this.queue.splice(0, 1);return value;} }使用extends繼承。
為什么? 因?yàn)?extends 是一個(gè)內(nèi)建的原型繼承方法并且不會(huì)破壞 instanceof。 // bad const inherits = require('inherits'); function PeekableQueue(contents) {Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function () {return this.queue[0]; };// good class PeekableQueue extends Queue {peek() {return this.queue[0];} }方法可以返回 this 來(lái)幫助鏈?zhǔn)秸{(diào)用。
// bad Jedi.prototype.jump = function () {this.jumping = true;return true; };Jedi.prototype.setHeight = function (height) {this.height = height; };const luke = new Jedi(); luke.jump(); // => true luke.setHeight(20); // => undefined// good class Jedi {jump() {this.jumping = true;return this;}setHeight(height) {this.height = height;return this;} }const luke = new Jedi();luke.jump().setHeight(20);可以寫一個(gè)自定義的 toString() 方法,但要確保它能正常運(yùn)行并且不會(huì)引起副作用。
class Jedi {constructor(options = {}) {this.name = options.name || 'no name';}getName() {return this.name;}toString() {return `Jedi - ${this.getName()}`;} }類有默認(rèn)構(gòu)造器。一個(gè)空的構(gòu)造函數(shù)或者只是重載父類構(gòu)造函數(shù)是不必要的。eslint: no-useless-constructor
// bad class Jedi {constructor() {}getName() {return this.name;} }// bad class Rey extends Jedi {constructor(...args) {super(...args);} }// good class Rey extends Jedi {constructor(...args) {super(...args);this.name = 'Rey';} }避免重復(fù)的類成員。eslint: no-dupe-class-members
為什么?重復(fù)的類成員聲明中只有最后一個(gè)生效-重復(fù)的聲明肯定是一個(gè)錯(cuò)誤。 // bad class Foo {bar() { return 1; }bar() { return 2; } }// good class Foo {bar() { return 1; } }// good class Foo {bar() { return 2; } }模塊
總是使用模組 (import/export) 而不是其他非標(biāo)準(zhǔn)模塊系統(tǒng)。你可以編譯為你喜歡的模塊系統(tǒng)。
為什么?模塊是未來(lái),讓我們開(kāi)始邁向未來(lái)吧。 // bad const AirbnbStyleGuide = require('./AirbnbStyleGuide'); module.exports = AirbnbStyleGuide.es6;// ok import AirbnbStyleGuide from './AirbnbStyleGuide'; export default AirbnbStyleGuide.es6;// best import { es6 } from './AirbnbStyleGuide'; export default es6;不要使用通配符 import
為什么?這樣確保只有一個(gè)默認(rèn)的export // bad import * as AirbnbStyleGuide from './AirbnbStyleGuide';// good import AirbnbStyleGuide from './AirbnbStyleGuide';不要直接從import中export
為什么?雖然一行代碼簡(jiǎn)潔明了,但讓 import 和 export 各司其職讓事情能保持一致。 // bad // filename es6.js export { es6 as default } from './AirbnbStyleGuide';// good // filename es6.js import { es6 } from './AirbnbStyleGuide'; export default es6;同一個(gè)路徑只使用一次import。eslint: no-duplicate-imports
為什么?相同路徑有多個(gè)import會(huì)導(dǎo)致代碼難以維護(hù)。 // bad import foo from 'foo'; // … some other imports … // import { named1, named2 } from 'foo';// good import foo, { named1, named2 } from 'foo';// good import foo, {named1,named2, } from 'foo';不要export可變的綁定。 eslint: import/no-mutable-exports
為什么?避免不確定的可變量,特別是export可變的綁定。如果某些特殊情況需要使用這種場(chǎng)景,通常應(yīng)該export常量引用。 // bad let foo = 3; export { foo };// good const foo = 3; export { foo };模塊中只有單個(gè)export,最好使用default export 。 eslint: import/prefer-default-export
為什么?一個(gè)文件最好只做一件事,這樣更具備可讀性和可維護(hù)性。 // bad export function foo() {}// good export default function foo() {}將所有的import語(yǔ)句放在文件的頂部。eslint: import/first
為什么?由于imports會(huì)被提升,最好保持它們?cè)陧敳恳苑莱霈F(xiàn)不可預(yù)期的行為。 // bad import foo from 'foo'; foo.init();import bar from 'bar';// good import foo from 'foo'; import bar from 'bar';foo.init();多行import應(yīng)該和多行數(shù)組和對(duì)象一樣有縮進(jìn)。
為什么?花括號(hào)需要遵循與指南中的每個(gè)其他花括號(hào)相同的縮進(jìn)規(guī)則,末尾的逗號(hào)也一樣。 // bad import {longNameA, longNameB, longNameC, longNameD, longNameE} from 'path';// good import {longNameA,longNameB,longNameC,longNameD,longNameE, } from 'path';禁止在模塊導(dǎo)入語(yǔ)句中使用Webpack加載器語(yǔ)法。eslint: import/no-webpack-loader-syntax
為什么?在import中使用webpack 語(yǔ)法會(huì)將代碼耦合進(jìn)bundler中。推薦在webpack.config.js中配置loader 規(guī)則。 // bad import fooSass from 'css!sass!foo.scss'; import barCss from 'style!css!bar.css';// good import fooSass from 'foo.scss'; import barCss from 'bar.css';總結(jié)
以上是生活随笔為你收集整理的Airbnb JavaScript 编码风格指南(2018年最新版)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Swift学习之map、flatMap、
- 下一篇: c语言程序设计第3周编程作业(数字特征)