【譯】12個編寫乾淨且可擴展的JavaScript技巧

JavaScript起源於早期的網絡。 從做爲腳本語言開始,到如今它已經發展成爲一種徹底成熟的編程語言,而且支持服務器端執行。javascript

現代Web應用程序嚴重依賴JavaScript,尤爲是單頁應用程序(SPA)。藉助於React,AngularJS和Vue.js等新興框架,Web應用程序主要使用JavaScript構建。前端

擴展這些應用程序有時候會比較棘手,經過簡單的設置,您最終可能會遇到限制並迷失在混亂的海洋中。我想分享一些小技巧,這些技巧將幫助您以有效的方式編寫乾淨的代碼。java

本文面向任何技能水平的JavaScript開發人員。 可是,至少具備JavaScript中級知識的開發人員將從這些技巧中獲益最多。react

原文連接:blog.logrocket.com/12-tips-for…git

分隔您的代碼

我建議保持代碼庫清潔和可讀的最重要的事情是具備按主題分隔的特定邏輯塊(一般是函數)。若是你編寫一個函數,該函數應該默認只有一個目的,不該該一次作多個事情。github

此外,您應避免引發反作用,這意味着在大多數狀況下,您不該更改在函數外聲明的任何內容。 您將數據接收到帶參數的函數中;其餘一切都不該該被訪問。若是您但願從函數中獲取某些內容,請返回新值。npm

模塊化

固然,若是以相似的方式使用這些函數或執行相似的操做,您能夠將多個函數分組到一個模塊(and/or 的類中)。例如,若是要進行許多不一樣的計算,請將它們拆分爲能夠連接的獨立步驟(函數)。可是,這些函數均可以在一個文件(模塊)中聲明。 如下是JavaScript中的示例:編程

function add(a, b) {
    return a + b   
}

function subtract(a, b) {
    return a - b   
}

module.exports = {
    add,
    subtract
}

const { add, subtract } = require('./calculations')

console.log(subtract(5, add(3, 2))
複製代碼

若是您正在編寫前端JavaScript,請務必使用默認導出做爲最重要的項目,併爲次要項目命名導出。數組

多個參數優先於單個對象參數

聲明一個函數時,您應該老是喜歡多個參數而不是一個指望對象的參數:服務器

// GOOD
function displayUser(firstName, lastName, age) {
    console.log(`This is ${firstName} ${lastName}. She is ${age} years old.`)
}

// BAD
function displayUser(user) {
    console.log(`This is ${user.firstName} ${user.lastName}. She is ${user.age} years old.`)
}
複製代碼

這背後的緣由是,當您查看函數聲明的第一行時,您能確切知道須要傳遞給函數的內容。

儘管函數應該受到限制 - 只作一項工做 - 可是它可能會變得更大。在函數體中掃描須要傳遞的變量(嵌套在對象中)將花費更多時間。有時,使用整個對象並將其傳遞給函數彷佛更容易,但爲了擴展應用程序,此設置確定會有所幫助。

在某種程度上,聲明特定參數沒有意義。對我來講,它超過四個或五個功能參數。若是你的函數變大,你應該轉向使用對象參數。

這裏的主要緣由是參數須要以特定順序傳遞。 若是您有可選參數,則須要傳遞undefined或null。 使用對象參數,您能夠簡單地傳遞整個對象,其中順序和未定義的值可有可無。

解構(Destructuring)

解構是ES6引入的一個很好的工具。它容許您從對象中獲取特定字段並當即將其分配給變量。 您能夠將它用於任何類型的對象或模塊。

// EXAMPLE FOR MODULES
const { add, subtract } = require('./calculations')
複製代碼

只導入您須要在文件中使用的函數而不是整個模塊,而後從中訪問特定的函數。 一樣,當您肯定您確實須要一個對象做爲函數參數時,也可使用destructuring。 這仍將爲您提供函數內所需內容的概述:

function logCountry({name, code, language, currency, population, continent}) {
    let msg = `The official language of ${name} `
    if(code) msg += `(${code}) `
    msg += `is ${language}. ${population} inhabitants pay in ${currency}.`
    if(contintent) msg += ` The country is located in ${continent}`
}

logCountry({
    name: 'Germany',
    code: 'DE',
    language 'german',
    currency: 'Euro',
    population: '82 Million',
})

logCountry({
    name: 'China',
    language 'mandarin',
    currency: 'Renminbi',
    population: '1.4 Billion',
    continent: 'Asia',
})
複製代碼

正如你所看到的,我仍然知道我須要傳遞什麼給函數 - 即便它被包裝在一個對象中。要解決了解所需內容的問題,請參閱下一個提示!(順便說一句,這也適用於React功能組件。)

使用默認值

解構的默認值甚至基本函數參數都很是有用。首先,它們爲您提供了一個能夠傳遞給函數的值的示例。其次,您能夠指出哪些值是必需的,哪些值不是。使用前面的示例,該函數的完整設置以下所示:

function logCountry({ name = 'United States', code, language = 'English', currency = 'USD', population = '327 Million', continent, }) {
    let msg = `The official language of ${name} `
    if(code) msg += `(${code}) `
    msg += `is ${language}. ${population} inhabitants pay in ${currency}.`
    if(contintent) msg += ` The country is located in ${continent}`
}

logCountry({
    name: 'Germany',
    code: 'DE',
    language 'german',
    currency: 'Euro',
    population: '82 Million',
})

logCountry({
    name: 'China',
    language 'mandarin',
    currency: 'Renminbi',
    population: '1.4 Billion',
    continent: 'Asia',
})
複製代碼

顯然,有時您可能不想使用默認值,而是在未傳遞值時拋出錯誤。 然而,這一般是一個方便的技巧。

數據稀缺性

前面的技巧引出了一個結論:最好不要傳遞您不須要的數據。一樣,在設置函數時,這可能意味着更多的工做。可是,從長遠來看,它確定會爲您提供更具可讀性的代碼庫。確切地知道在特定位置使用哪些值是很是有價值的。

行數和縮進限制

我見過大文件 - 很是大的文件。實際上,超過3,000行代碼。在這些文件中查找邏輯塊是很是困難的。

所以,您應該將文件大小限制爲必定數量的行。我傾向於將個人文件保存在100行代碼之下。 有時候,很難分解文件,它們會增加到200-300行,在極少數狀況下會增長到400行。

超過此臨界值,意味着文件太雜亂,難以維護。隨意建立新的模塊和文件夾。您的項目應該看起來像一個森林,由樹(模塊部分)和分支(模塊和模塊文件組)組成。避免試圖模仿阿爾卑斯山,在密閉區域堆積代碼。

相比之下,你的實際文件應該看起來像Shire,這裏和那裏都有一些山丘(小水平的縮進),但一切都相對平坦。 儘可能將壓痕水平保持在四級如下。

也許爲這些提示啓用eslint規則是有幫助的!

使用prettier

在團隊中工做須要清晰的樣式指南和格式。ESLint提供了一個巨大的規則集,您能夠根據本身的需求進行自定義。還有 eslint--fix,它能夠糾正一些錯誤,但不是所有。

相反,我建議使用Prettier格式化代碼。這樣,開發人員沒必要擔憂代碼格式化,而只需編寫高質量的代碼。 外觀將一致而且格式自動化。

使用有意義的變量名

理想狀況下,應根據其內容命名變量。 如下是一些有助於您聲明有意義的變量名稱的指南。

函數

函數一般執行某種操做。爲了解釋這一點,人類使用動詞 - 轉換或顯示,例如。在開頭用動詞命名函數是個好主意,例如convertCurrencydisplayUserName

數組

這些一般會包含一系列項目; 所以,將s附加到變量名稱。 例如:

const students = ['Eddie', 'Julia', 'Nathan', 'Theresa']
複製代碼

布爾

簡單地說就是儘可能多接近於天然語言,這樣好理解。你會問「這我的是教師嗎?」→「是」或「否」。一樣:

const isTeacher = true // OR false
複製代碼

數組函數

forEach, map, reduce, filter等是很好的原生JavaScript函數,用於處理數組和執行某些操做。 我看到不少人只是將elelement做爲參數傳遞給回調函數。 雖然這很簡單快捷,但您還應根據其值來命名。 例如:

const cities = ['Berlin', 'San Francisco', 'Tel Aviv', 'Seoul']
cities.forEach(function(city) {
...
})
複製代碼

標識

一般,您必須跟蹤特定數據集和對象的ID。當嵌套id時,只需將其保留爲id便可。在這裏,我喜歡在將對象返回到前端以前將MongoDB _id映射到 id。從對象中提取id時,請預先添加對象的類型。例如:

const studentId = student.id
// OR
const { id: studentId } = student // destructuring with renaming
複製代碼

該規則的一個例外是模型中的MongoDB引用。 在這裏,只需在引用的模型以後命名字段便可。 這將在填充參考文檔時保持清晰:

const StudentSchema = new Schema({
    teacher: {
        type: Schema.Types.ObjectId,
        ref: 'Teacher',
        required: true,
    },
    name: String,
    ...
})
複製代碼

儘量使用async / await

在可讀性方面,回調是最糟糕的 - 特別是在嵌套時。Promises是一個很好的改進,但在我看來,async / await具備最好的可讀性。即便對於初學者或來自其餘語言的人來講,這也會有很大幫助。可是,請確保您瞭解其背後的概念,而且不要盲目地在任何地方使用它。

模塊導入順序

正如咱們在技巧1和2中看到的那樣,將邏輯保持在正確的位置是可維護性的關鍵。 一樣,導入不一樣模塊的方式能夠減小文件中的混淆。 我在導入不一樣模塊時遵循一個簡單的結構:

// 3rd party packages
import React from 'react'
import styled from 'styled-components'

// Stores
import Store from '~/Store

// reusable components
import Button from '~/components/Button'

// utility functions
import { add, subtract } from '~/utils/calculate'

// submodules
import Intro from './Intro'
import Selector from './Selector'
複製代碼

我在這裏使用了React組件做爲示例,由於有更多類型的導入。 您應該可以根據您的具體用例進行調整。

擺脫控制檯

console.log 是一種很好的調試方式 - 很是簡單,快速,完成工做。顯然,有更復雜的工具,但我認爲每一個開發人員仍然使用它。若是您忘記清理日誌,您的控制檯最終將陷入巨大的混亂。而後,您確實要在代碼庫中保留日誌; 例如,警告和錯誤。

要解決此問題,您仍然可使用console.log 進行調試,但對於持久日誌,請使用loglevelwinston等庫。此外,您可使用ESLint警告控制檯語句。這樣你就能夠輕鬆地全局查找console... 並刪除這些語句。

遵循這些指導原則確實幫助我保持代碼庫的清潔和可擴展性。 你以爲還有什麼提示特別有用的嗎?請在評論中告訴我您在編碼工做過程當中值得推薦的內容,並請分享您用於幫助代碼結構的任何其餘提示!謝謝~

若是以爲文章對你有些許幫助,歡迎在個人GitHub博客點贊和關注,感激涕零!

相關文章
相關標籤/搜索