格實(shí)戰(zhàn):從《不好的風(fēng)格》練習(xí)看如何識(shí)別并修復(fù)代碼風(fēng)格問題)
文檔教程前端【免費(fèi)下載鏈接】zh.javascript.info現(xiàn)代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 規(guī)范為基準(zhǔn)通過簡單但足夠詳細(xì)的內(nèi)容為你講解從基礎(chǔ)到高階的 JavaScript 相關(guān)知識(shí)。項(xiàng)目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info點(diǎn)擊查看免費(fèi)下載本文基于 zh.javascript.info現(xiàn)代 JavaScript 教程代碼質(zhì)量章節(jié)中的實(shí)戰(zhàn)練習(xí)展開。該練習(xí)給出了一段“風(fēng)格很差但功能正確”的pow冪函數(shù)代碼要求讀者逐行找出風(fēng)格問題并修復(fù)。讀完本文你將能系統(tǒng)地識(shí)別函數(shù)簽名空格、花括號(hào)位置、運(yùn)算符兩側(cè)空格、分號(hào)缺失、超長行、多變量聲明等常見風(fēng)格缺陷并掌握一套可直接套用的修復(fù)方法文中還會(huì)結(jié)合 代碼風(fēng)格主文 的規(guī)則體系與 ESLint 等自動(dòng)檢查工具幫助你建立可落地的代碼風(fēng)格習(xí)慣。練習(xí)背景它在教程中的位置與考察目標(biāo)這段練習(xí)位于教程的 1-js/03-code-quality/02-coding-style 目錄下是“代碼風(fēng)格”一章的第一個(gè)任務(wù)題目本身存放在 task.md參考答案存放在 solution.md。該章的核心主張非常明確“我們的代碼必須盡可能的清晰和易讀”良好的代碼風(fēng)格是一項(xiàng)“編程藝術(shù)”——以正確且易于他人閱讀的方式完成復(fù)雜任務(wù)。練習(xí)的目的正是把這一抽象原則落到具體代碼上題目給出的代碼在語法上完全合法、能正確計(jì)算x的n次冪但充斥著大量風(fēng)格缺陷。學(xué)習(xí)者需要像“審稿人”一樣逐行挑出問題并給出修復(fù)版本。原始代碼一段“能跑但難看”的 pow 函數(shù)練習(xí)給出的原始代碼如下這就是 task.md 中待修復(fù)的版本function pow(x,n) { let result1; for(let i0;in;i) {result*x;} return result; } let xprompt(x?,), nprompt(n?,) if (n0) { alert(Power ${n} is not supported, please enter an integer number greater than zero); } else { alert(pow(x,n)) }功能上它完成了三件事定義pow(x, n)冪函數(shù)通過兩次prompt獲取x與n當(dāng)n 0時(shí)提示不支持否則彈出計(jì)算結(jié)果。但這段代碼在可讀性上有大量問題接下來我們對(duì)照 solution.md 中逐條標(biāo)注的注釋逐一剖析。逐條剖析代碼中的每一處風(fēng)格缺陷下面是在原始代碼上標(biāo)注出的全部問題。為了方便對(duì)照先看帶注釋的完整版本function pow(x,n) // - 參數(shù)之間沒有空格 { // - 花括號(hào)獨(dú)占了一行 let result1; // - 號(hào)兩邊沒有空格 for(let i0;in;i) {result*x;} // - 沒有空格 // { ... } 里面的內(nèi)容應(yīng)該在新的一行上 return result; } let xprompt(x?,), nprompt(n?,) // -- 從技術(shù)的角度來看是可以的 // 但是拆分成 2 行會(huì)更好并且這里也缺了空格和分號(hào) ; if (n0) // - (n 0) 里面沒有空格并且應(yīng)該在本行上面加一個(gè)空行 { // - 花括號(hào)獨(dú)占了一行 // 下面的一行代碼太長了可以將其拆分成 2 行以提高可讀性 alert(Power ${n} is not supported, please enter an integer number greater than zero); } else // - 可以像 } else { 這樣寫在一行上 { alert(pow(x,n)) // 缺失了空格和分號(hào) ; }缺陷一函數(shù)簽名中參數(shù)之間沒有空格function pow(x,n)中x與n之間缺少空格。教程的 代碼風(fēng)格主文 將“空格”視為代碼風(fēng)格的基礎(chǔ)語法要素并提供了完整的風(fēng)格備忘圖見下圖其中明確要求函數(shù)名與左括號(hào)之間、括號(hào)與參數(shù)之間都要有空格參數(shù)之間也要有空格。修復(fù)方式function pow(x, n)。缺陷二花括號(hào)獨(dú)占一行原始代碼把左花括號(hào){放在了單獨(dú)一行function pow(x,n) {主文在“花括號(hào)”一節(jié)中明確指出在大多數(shù) JavaScript 項(xiàng)目中花括號(hào)采用“Egyptian” 風(fēng)格即 KR 風(fēng)格—— 左花括號(hào)與相應(yīng)的關(guān)鍵詞位于同一行末尾而不是另起一行且左括號(hào)前應(yīng)有一個(gè)空格if (condition) { // do this // ...and that }因此{(lán)應(yīng)緊跟函數(shù)簽名function pow(x, n) {。類似的錯(cuò)誤在后面的if (n0)與else塊中重復(fù)出現(xiàn)屬于同一類問題。缺陷三賦值運(yùn)算符兩側(cè)沒有空格let result1;中兩側(cè)沒有空格。主文要求“運(yùn)算符周圍要有空格”這是提高可讀性的基礎(chǔ)規(guī)則。修復(fù)為let result 1;。缺陷四for 循環(huán)整體壓縮在一行、缺少空格、代碼塊未換行for(let i0;in;i) {result*x;}同時(shí)違反了幾條規(guī)則for關(guān)鍵字與左括號(hào)之間沒有空格主文要求for、if、while等關(guān)鍵詞后留空格循環(huán)頭部i0、in、i內(nèi)部以及分號(hào)后缺少空格循環(huán)體{result*x;}被壓在同一行。主文明確指出{ ... }里面的內(nèi)容應(yīng)該在新的一行上。修復(fù)為for (let i 0; i n; i) { result * x; }缺陷五用逗號(hào)在一行內(nèi)聲明多個(gè)變量let xprompt(x?,), nprompt(n?,)在語法上完全合法這也是原注釋所說“從技術(shù)的角度來看是可以的”但把兩次prompt擠在同一行既缺空格、又缺分號(hào)可讀性差。拆成兩行、每行一個(gè)變量聲明更清晰let x prompt(x?, ); let n prompt(n?, );缺陷六if 條件內(nèi)部沒有空格且上方缺少空行if (n0)中n0內(nèi)部沒有空格應(yīng)為n 0。同時(shí)這段if之前的let聲明與if之間沒有空行。主文在“縮進(jìn)”一節(jié)中專門講了垂直方向上的縮進(jìn)用空行把代碼拆分成邏輯塊。即使是一個(gè)函數(shù)也應(yīng)分割為“變量初始化 → 主邏輯 → 返回值”等邏輯塊寫代碼時(shí)不應(yīng)出現(xiàn)連續(xù)超過 9 行都沒有被垂直分割的情況。因此let聲明與if之間應(yīng)插入一個(gè)空行。缺陷七單行過長alert(Power ${n} is not supported, please enter an integer number greater than zero);這一行太長。主文在“行的長度”一節(jié)中指出沒有人喜歡讀一長串代碼最好將代碼分割一下。一行最大長度應(yīng)由團(tuán)隊(duì)達(dá)成一致通常是 80 或 120 個(gè)字符。模板字符串反引號(hào)天然支持跨行因此可以把這條提示信息拆成兩行alert(Power ${n} is not supported, please enter an integer number greater than zero);主文中還給出了if條件過長時(shí)的拆行示范——把多個(gè)條件縱向排列每個(gè)條件一行if ( id 123 moonPhase Waning Gibbous zodiacSign Libra ) { letTheSorceryBegin(); }缺陷八else 單獨(dú)占一行else獨(dú)占一行不如寫成} else {。主文在花括號(hào)一節(jié)的示例if (condition) { ... }以及風(fēng)格備忘圖中都體現(xiàn)了這一點(diǎn)閉合花括號(hào)與else、下一個(gè)左花括號(hào)連寫在一行上整體結(jié)構(gòu)更緊湊、塊歸屬一目了然。缺陷九函數(shù)調(diào)用缺少空格與分號(hào)alert(pow(x,n))存在兩個(gè)問題嵌套調(diào)用pow(x,n)內(nèi)部沒有空格應(yīng)為pow(x, n)且語句末尾缺少分號(hào)。主文在“分號(hào)”一節(jié)中強(qiáng)調(diào)每一個(gè)語句后面都應(yīng)該有一個(gè)分號(hào)即使它可以被跳過——因?yàn)樵跇O少數(shù)情況下JavaScript 的換行符不會(huì)被解釋為分號(hào)容易埋下隱患詳見 分號(hào)一節(jié)。修復(fù)為alert( pow(x, n) );修復(fù)后的完整版本綜合以上所有修正solution.md 給出的參考答案如下function pow(x, n) { let result 1; for (let i 0; i n; i) { result * x; } return result; } let x prompt(x?, ); let n prompt(n?, ); if (n 0) { alert(Power ${n} is not supported, please enter an integer number greater than zero); } else { alert( pow(x, n) ); }對(duì)比前后兩個(gè)版本可以看到函數(shù)體內(nèi)變量初始化、循環(huán)邏輯、返回值之間用空行做了垂直分割for循環(huán)體獨(dú)占一行并縮進(jìn)兩個(gè)空格if/else以} else {形式連接所有運(yùn)算符、逗號(hào)、括號(hào)前后都保留了規(guī)范的空格每條語句都以分號(hào)結(jié)尾。功能完全不變但可讀性有了質(zhì)的提升。這也是 代碼風(fēng)格主文 開頭給出的規(guī)范示例風(fēng)格主文中n 0版本的完整范本可參見該文“語法”一節(jié)。從“改對(duì)”到“寫對(duì)”支撐這些規(guī)則的原理練習(xí)只要求修復(fù)一段代碼但真正重要的是理解每條規(guī)則背后的理由。結(jié)合 代碼風(fēng)格主文可以把本練習(xí)涉及的規(guī)則歸納為幾組花括號(hào)選擇哪種寫法主文對(duì)比了if的四種寫法if (n 0) {alert(...)}—— 初學(xué)者常把花括號(hào)與語句擠在一行非常不好if (n 0)換行后再寫alert(...)、不加花括號(hào) —— 永遠(yuǎn)不要這樣做添加新行很容易出錯(cuò)if (n 0) alert(...)單行無花括號(hào) —— 如果代碼很短可以接受if (n 0) { ... }——最好的方式。本練習(xí)中的if (n0)恰好屬于第 1 類的變形花括號(hào)另起一行應(yīng)改為第 4 類寫法。對(duì)于極短語句如if (cond) return null單行寫法也是可接受的但塊結(jié)構(gòu)通常更具可讀性??s進(jìn)水平與垂直兩個(gè)維度水平縮進(jìn)通常為 2 或 4 個(gè)空格或 Tab。如今空格更普遍因?yàn)榭崭窨梢员?Tab 做出更靈活的縮進(jìn)配置例如把函數(shù)參數(shù)與左括號(hào)對(duì)齊。本練習(xí)統(tǒng)一采用 2 空格縮進(jìn)。垂直縮進(jìn)用空行把代碼拆分成邏輯塊。本練習(xí)在result初始化、for循環(huán)、return之間以及l(fā)et聲明與if之間插入空行正是這一原則的體現(xiàn)。嵌套層級(jí)盡量淺主文建議盡量避免過深嵌套例如循環(huán)內(nèi)不要層層加if可以用continue提前跳出for (let i 0; i 10; i) { if (!cond) continue; ... // - 沒有額外的嵌套 }if/else與return的組合也可以達(dá)到同樣效果把“特殊情況”在一開始就處理掉例如n 0時(shí)直接return主代碼流就不需要額外嵌套。本練習(xí)的pow函數(shù)雖然嵌套不深但else分支的寫法同樣可以套用這一思路——條件不滿足時(shí)立即結(jié)束主體邏輯平鋪展開。函數(shù)位置先調(diào)用、后定義主文指出如果代碼中有“輔助函數(shù)”與調(diào)用它們的代碼組織方式有三種函數(shù)在上、調(diào)用在下調(diào)用在上、函數(shù)在下混合式。大多數(shù)情況下“先寫調(diào)用代碼、再寫函數(shù)”更好因?yàn)殚喿x時(shí)我們首先想知道的是“它做了什么”。本練習(xí)中pow先定義后調(diào)用屬于第 1 種方式在課堂練習(xí)中完全合理但在真實(shí)項(xiàng)目中把“做什么”的調(diào)用代碼放在前面往往更利于他人快速理解程序主干。把規(guī)則自動(dòng)化風(fēng)格指南與檢查器Linters人工逐行審查難免遺漏團(tuán)隊(duì)協(xié)作時(shí)更需要統(tǒng)一標(biāo)準(zhǔn)。主文介紹了兩類工具化手段風(fēng)格指南風(fēng)格指南是“如何編寫代碼”的通用規(guī)則集涵蓋用哪個(gè)引號(hào)、縮進(jìn)幾個(gè)空格、一行最大長度等細(xì)節(jié)。當(dāng)團(tuán)隊(duì)所有成員遵循同一份指南時(shí)無論代碼由誰編寫風(fēng)格都是統(tǒng)一的。業(yè)界已有多種成熟方案可供選擇如 Google、Airbnb、Idiomatic.JS、StandardJS 等初學(xué)者可以從本文這類基礎(chǔ)規(guī)則起步再挑選自己偏好的指南。ESLint 等自動(dòng)檢查器檢查器Linters可以自動(dòng)檢查代碼風(fēng)格并提出改進(jìn)建議而且順帶能發(fā)現(xiàn)變量或函數(shù)名拼寫錯(cuò)誤等真實(shí) bug——因此即使不打算固守某種風(fēng)格也建議安裝一個(gè)。主文提到 JSLint、JSHint、ESLint 等工具并給出了 ESLint 的啟用流程安裝 Node.js使用npm install -g eslint安裝 ESLint在項(xiàng)目根目錄創(chuàng)建.eslintrc配置文件在編輯器中安裝/啟用 ESLint 插件。主文給出的.eslintrc示例{ extends: eslint:recommended, env: { browser: true, node: true, es6: true }, rules: { no-console: 0, indent: 2 } }其中extends: eslint:recommended表示基于 ESLint 的推薦規(guī)則集進(jìn)行設(shè)置然后通過rules覆蓋或追加自定義規(guī)則——例如示例中把縮進(jìn)規(guī)則設(shè)定為 2 空格indent: 2與本練習(xí)采用的縮進(jìn)風(fēng)格完全一致。把本練習(xí)中發(fā)現(xiàn)的“缺陷類型”空格缺失、分號(hào)缺失、花括號(hào)位置、行過長等交給檢查器自動(dòng)把關(guān)正是“從人工修復(fù)到機(jī)器預(yù)防”的最佳實(shí)踐路徑??偨Y(jié)一份可復(fù)用的代碼風(fēng)格自查清單回到本練習(xí)把 solution.md 揭示的九類問題整理成清單即可作為日常自查的速查表參數(shù)與括號(hào)函數(shù)名與(之間、參數(shù)之間、嵌套調(diào)用參數(shù)之間都要有空格花括號(hào)位置左花括號(hào)與關(guān)鍵詞同行KR 風(fēng)格} else {連寫在一行運(yùn)算符空格、、*等運(yùn)算符兩側(cè)保留空格控制結(jié)構(gòu)for、if、while后留空格循環(huán)體內(nèi)容換行、縮進(jìn)變量聲明每行一個(gè)變量使用let x ...;完整寫法并加結(jié)尾分號(hào)空行分割不同邏輯塊之間用空行做垂直分割行長度超過團(tuán)隊(duì)約定通常 80/120 字符時(shí)拆分模板字符串可跨行分號(hào)每條語句末尾都寫分號(hào)嵌套深度用continue、提前return減少嵌套層級(jí)。主文在“總結(jié)”一節(jié)給出的判斷標(biāo)準(zhǔn)值得反復(fù)體會(huì)當(dāng)我們思考如何寫“更好”的代碼時(shí)應(yīng)該問自己兩個(gè)問題——“什么可以讓代碼可讀性更高、更容易被理解”以及“什么可以幫助我們避免錯(cuò)誤”本練習(xí)的每一處修復(fù)最終都服務(wù)于這兩個(gè)目標(biāo)。贊分享文檔教程前端【免費(fèi)下載鏈接】zh.javascript.info現(xiàn)代 JavaScript 教程The Modern JavaScript Tutorial以最新的 ECMAScript 規(guī)范為基準(zhǔn)通過簡單但足夠詳細(xì)的內(nèi)容為你講解從基礎(chǔ)到高階的 JavaScript 相關(guān)知識(shí)。項(xiàng)目地址https://gitcode.com/gh_mirrors/zh/zh.javascript.info點(diǎn)擊查看免費(fèi)下載相關(guān)推薦修復(fù) JavaScript 糟糕代碼風(fēng)格以 pow 函數(shù)練習(xí)剖析編碼規(guī)范javascript.info 編碼風(fēng)格實(shí)戰(zhàn)修復(fù) JavaScript 糟糕代碼風(fēng)格以 pow 函數(shù)練習(xí)剖析編碼規(guī)范javascript.info 編碼風(fēng)格實(shí)戰(zhàn) 整潔、易讀的代碼與正確運(yùn)行的代碼同文檔/教程前端終極idiomatic.js代碼審查寶典快速識(shí)別和修復(fù)JavaScript代碼風(fēng)格問題終極idiomatic.js代碼審查寶典快速識(shí)別和修復(fù)JavaScript代碼風(fēng)格問題 idiomatic.js是一個(gè)專注于編寫一致、地道JavaScript1BRC代碼風(fēng)格統(tǒng)一代碼風(fēng)格與格式化規(guī)范1BRC代碼風(fēng)格統(tǒng)一代碼風(fēng)格與格式化規(guī)范 概述 在十億行挑戰(zhàn)1BRC這個(gè)高性能計(jì)算項(xiàng)目中代碼風(fēng)格的一致性對(duì)于項(xiàng)目維護(hù)和性能優(yōu)化至關(guān)重要。本文深入探討1B性能測試大數(shù)據(jù)上一篇3分鐘極速部署為華碩路由器打造全網(wǎng)廣告攔截系統(tǒng)下一篇如何安裝 Mac Mouse Fix為 Mac 鼠標(biāo)選對(duì)安裝方式并設(shè)置平滑滾動(dòng)的完整指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考