【譯】2019 年 JavaScript 開發者應該都在用的 9 個棒的技巧

原文連接: 9 Tricks for Kickass JavaScript Developers in 2019
github 的地址 歡迎 star!
固然做者是在今年1月份寫的!我感受大部分功能都已經使用好久啦,你們看看就好啦,就當總結回顧
javascript

前言

又一年過去了,JavaScript 也一直在變化進步着。這兒列舉了一些小技巧幫你在 2019 年寫出更簡潔,高效的可拓展的代碼。下面共列舉了 9 個講究使用的小技巧來幫助你成爲更好的開發者。css

1. async / await

若是你還陷入到回調地獄中,那麼你應該回到 2014 年去開發你的代碼。除非絕對必要(像第三方庫須要或者性能緣由),不然不要使用回調。Promise 是很是好的解決回調地獄,可是當你的代碼變得愈來愈大時,它也會變得不太好用。我如今的解決方案就是 async / await,它極大提升了代碼可讀性以及簡潔性。在全部使用Promise的地方你均可以替換成 await,在你須要返回 Promise 對象,簡單 await 它並返回,爲了使它不報錯,你須要在定義函數的開頭添加 async。事實上,async / await 就是 Promise 的語法糖。下面就是一個簡單的例子:html

async function getData() {
    const result = await axios.get('https://dube.io/service/ping')
    const data = result.data
    
    console.log('data', data)
    
    return data
}

getData()
// 對於在外部要使用getData中數據的話,是要 await getData()取到data的,async老是返回一個Promise對象
複製代碼

await 操做符用於等待一個 Promise 對象。它只能在異步函數 async function 中使用。 async / await是屬於 ES2017 的內容,因此可能須要 babel 編譯你的代碼。不過如今的主流瀏覽器都已經支持了。前端

另外推薦 justjavac 大神翻譯的 await、return 和 return await 的陷阱以及這篇翻譯 javascript-async-await-the-good-part-pitfalls-and-how-to-use 能夠更加詳細的理解相關知識。java

2. 異步控制流

常常地,咱們會遇到這樣的需求,請求獲取多個數據集並對每一個數據集進行各自處理或者須要等全部異步回調完成後返回一個值。遇到這些狀況,我是這麼處理的:react

for…of

假設咱們的頁面有多個 Pokemon(口袋妖怪),須要獲取到它們的詳細的信息。咱們不想等全部調用結束,特別是不知道它有多少次調用,咱們僅想在它有調用返回時就更新咱們的數據集。能夠用 for…of 來遍歷數組,在代碼塊裏執行 async,這樣的話,只有每次 await 執行成功,代碼纔會繼續往下執行。 這裏要着重說明,這樣作可能會致使性能瓶頸(當請求不少的時候),但像這樣作才能到達預期的效果。請看下面的例子:webpack

import axios from 'axios'

let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}]

async function fetchData(dataSet) {
    for(entry of dataSet) {
        const result = await axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`)
        const newData = result.data
        updateData(newData)
        
        console.log(myData)
    }
}

function updateData(newData) {
    myData = myData.map(el => {
        if(el.id === newData.id) return newData
        return el
    })
}
    
fetchData(myData)
複製代碼

這個代碼是能正常運行,你能夠輕鬆地複製它到 code sandbox 運行。ios

Promise.all

若是你想同時獲取全部口袋妖怪的詳情呢?你須要等待全部的請求的完成返回,這時簡單使用 Promise.allgit

import axios from 'axios' 

let myData = [{id: 0}, {id: 1}, {id: 2}, {id: 3}]

async function fetchData(dataSet) {
    const pokemonPromises = dataSet.map(entry => {
        return axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`)
    })

    const results = await Promise.all(pokemonPromises)
    
    results.forEach(result => {
        updateData(result.data)
    })
    
    console.log(myData) 
}

function updateData(newData) {
    myData = myData.map(el => {
        if(el.id === newData.id) return newData
        return el
    })
}
    
fetchData(myData)
複製代碼

for...of 和 Promise.all都是 ES6 之後提出來的,請確保你的環境能運行。github

3. 解構(Destructuring ) & 默認值

咱們接着上面的那個例子,提取一部分代碼:

const result = axios.get(`https://ironhack-pokeapi.herokuapp.com/pokemon/${entry.id}`)
const data = result.data
複製代碼

有一種簡單的方法,解構從數組,或對象中獲取一些屬性(值)。像這樣:

const { data } = await axios.get(...)
複製代碼

你也能夠重命名你的變量

const { data: newData } = await axios.get(...)
複製代碼

注意當解構的時候,一般要賦給它一個默認值。這樣確保你不會獲得undefined以及你不用本身手動地檢查變量。

const { id = 5 } = {}
console.log(id) // 5
複製代碼

這個技巧也被運用到了函數參數中。例如:

function calculate({operands = [1, 2], type = 'addition'} = {}) {
    return operands.reduce((acc, val) => {
        switch(type) {
            case 'addition':
                return acc + val
            case 'subtraction':
                return acc - val
            case 'multiplication':
                return acc * val
            case 'division':
                return acc / val
        }
    }, ['addition', 'subtraction'].includes(type) ? 0 : 1)
}

console.log(calculate()) // 3
console.log(calculate({type: 'division'})) // 0.5
console.log(calculate({operands: [2, 3, 4], type: 'multiplication'})) // 24
複製代碼

這個例子起初看起來可能有點混亂,可是慢慢觀察。當咱們沒有給函數傳遞參數的時候,就會使用默認值。一旦咱們開始傳遞參數,僅會使用那些沒有傳遞的參數的默認值。這樣,減小了你對異常狀態的處理。

4. 真值 & 假值

當使用默認值,就能夠不用對現有值進行一些額外的檢查。可是瞭解你的變量是真值仍是假值是很是棒的。它能提升你的代碼擴展性,更具備說服力的以及簡潔。我常看到下面一些寫法:

if(myBool === true) {
  console.log(...)
}
// OR
if(myString.length > 0) {
  console.log(...)
}
// OR
if(isNaN(myNumber)) {
  console.log(...)
}
複製代碼

能夠簡潔爲:

if(myBool) {
  console.log(...)
}
// OR
if(myString) {
  console.log(...)
}
// OR
if(!myNumber) {
  console.log(...)
}
<!-- 固然做者這裏的類比可能有必定問題,0!= NaN ,!myNumber是把範圍都擴大了,若是需求是隻要判斷是否NaN,仍是應該要用isNaN的方法-->
複製代碼

爲了用這些簡潔的判斷,你要充分理解js中真值,假值具體有哪些?這裏概述一下:

假值:

  1. 字符串,但長度爲0
  2. 數字0
  3. false
  4. undefined
  5. null
  6. NaN

真值

  1. 空數組
  2. 空對象
  3. 其餘有值的數據 注意:在判斷真/假值,還應該注意到你使用的是等於'==',仍是全等'===',這常常會致使 bug。對我而言,常常是數字 0。

5. 邏輯運算與三元運算符

邏輯運算

邏輯運算是基於多個表達式真假的判斷,注意到js是惰性求值的策略。邏輯運算通常返回一個布爾值。&& 和 || 運算符會返回一個指定操做數的值。來看這裏:

console.log(true && true) // true
console.log(false && true) // false
console.log(true && false) // false
console.log(false && false) // false
console.log(true || true) // true
console.log(true || false) // true
console.log(false || true) // true
console.log(false || false) // false
複製代碼

進行的邏輯運算,是按照下面的規則進行的:

  • &&:第一個值爲假值,則直接返回;若是爲真值,則直接返回第二的值

  • ||:第一個值爲真,則直接返回;若是爲假,則直接返回第二的值。

console.log(0 && {a: 1}) // 0
console.log(false && 'a') // false
console.log('2' && 5) // 5
console.log([] || false) // []
console.log(NaN || null) // null
console.log(true || 'a') // true
複製代碼

三元運算符

三元運算符和邏輯運算是類似的,可是它有3個部分: condition ? expr1 : expr2

  1. condition爲進行條件判斷的部分,將會獲得真值或者假值
  2. expr1爲條件判斷爲真時返回的值
  3. expr2爲條件判斷爲假時返回的值

例如:

const lang = 'German'
console.log(lang === 'German' ? 'Hallo' : 'Hello') // Hallo
console.log(lang ? 'Ja' : 'Yes') // Ja
console.log(lang === 'French' ? 'Bon soir' : 'Good evening') // Good evening
複製代碼

6. Optional Chaining

過去在 Object 屬性鏈的調用中,很容易由於某個屬性不存在而致使以後出現 Cannot read property xxx of undefined 的錯誤。爲了確認須要向這樣處理:

let data
if(myObj && myObj.firstProp && myObj.firstProp.secondProp && myObj.firstProp.secondProp.actualData) data = myObj.firstProp.secondProp.actualData
複製代碼

這樣事冗餘的,有一個新的提案的方法就是 Optional Chaining,以下的形式:

const data = myObj?.firstProp?.secondProp?.actualData
複製代碼

我認爲它是檢查嵌套屬性最佳方法,代碼是如此的簡潔。

這個特性能夠說是很是實用了,不過它如今處於 stage-1 階段。你能夠在.babelrc文件中引入 @babel/plugin-proposal-optional-chaining插件來使用它。

7. Class properties & binding

在 JavaScript 中函數綁定也是常常的工做任務。如今,你們應該都是用箭頭函數自動綁定 this 到這個類上的(這裏可能有歧義,首先箭頭函數裏面是沒有 this 和 arguments 的,這裏的 this 把它當成一個參數就行)。若是不用箭頭函數,咱們就須要在構造函數綁定 this,當類的方法不少的時候,這就顯得很冗餘。所以,建議和提倡在類裏面用箭頭函數。如:

class Counter extends React.Component {
    constructor(props) {
        super(props)
        this.state = { count: 0 }
    }
    
    render() {
        return(
            <div>
                <h1>{this.state.count}</h1>  
                <button onClick={this._increaseCount}>Increase Count</button>
            </div>
        )
    }
    
    _increaseCount = () => {
        this.setState({ count: this.state.count + 1 })
    }
}
複製代碼

關於必須 bind 傳參的狀況能夠看看個人另一篇文章

使用箭頭函數聲明類中方法,它如今處於 stage-3 階段。你能夠在.babelrc文件中引入@babel/plugin-proposal-class-properties插件來使用它。

8.使用parcel

做爲一個前端,你也確定會遇到打包和編譯代碼狀況。彷佛 webpack 成爲標準已經很長時間了。我從 webpack 1 版本就開始使用它了,固然那是痛苦的。爲了弄懂它全部的配置項,我花了無數的時間才讓它正常打包和編譯。若是還有選擇的機會,我是不會學習webpack的。恰巧幾個月前用了 parcel,歷來沒有發現配置能夠如此簡單!你不須要改動什麼便能獲得你預期的效果,固然你也能夠修改配置項。它也是和 webpack 或 babel 同樣是可配置的,同時也是快速的。若是你不知道 parcel,我明確建議你去學習它!

固然,如今的主流標準仍是 webpack,webpack 4 以後配置也簡潔了,能夠在學習 parcel 以後瞭解 webpack,不說了,又要開始學習 webpack 5

9. 寫更多你本身的代碼

談到這個話題,我有不少想要分享討論的東西。對於css,許多人更傾向於使用第三方組件庫像 bootstrap。對於 JavaScript,我也看到不少人喜歡用 jQuery 以及一些小型的驗證,滾動的庫等等。雖然使用庫是方便的,可是我強烈建議你能本身實現它,而不是盲目的安裝 npm 包。當它變成一個很大的庫或者框架的時候,整個團隊都要構建它,像 moment.js或者 react-datepicker,並且當需求發生改變時,你想要改動它是困難的。因此,你應該寫更多本身的組件。這將會帶來三個重要的優勢:

  1. 你很清楚你的代碼發生了什麼
  2. 同時,在你本身動手實現的過程當中,你也能真正開始明白何爲編程,以及庫中代碼是怎麼運行的
  3. 你能阻止你的代碼變得臃腫

在開始,使用 npm 包是方便的。你能花更多時間去實現本身的業務邏輯。但當那個包沒有按照預期運行時,你又換了一個包,這時不得不花更多時間去讀它的 API 才能使用它。當是你本身實現的庫(組件)時,你能百分百用本身的用例來定製化開發它。

我很是贊同這個的評論:不少人被'不要重複造輪子'的格言所困擾,由於他們把它理解成'不要重複實現輪子',對於一個熱愛編程的人,老是要有好奇心和不斷鑽研的,但願你們和我同樣謹記!

實現本身的輪子是多麼有成就感的一件事情! 後續我也會把本身的輪子放在github上。

總結

文中提到的點其實都是基礎,但實用的。對於新手 JavaScript 開發者,其實我更建議應該開始學習 TypeScript 了。由於它實在太好了!這裏給出了本身學習 TypeScript 一些歷程

若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝!

相關文章
相關標籤/搜索