原文連接:9 Tricks for Kickass JavaScript Developers in 2019
原文做者:Lukas Gisder-Dubé
譯者:JintNiu
推薦理由:JavaScript
已經成爲了當今使用最爲普遍、最受歡迎的語言之一,掌握一些使用技巧不只能夠提升開發效率,更有利於思惟轉換。javascript
過去的一年, JavaScript
在持續變化着,其使用範圍也愈來愈廣。接下來,我將針對 JavaScript
的使用,列出 9 條 建議,以幫助你寫出更加整潔高效的代碼,成爲更好的開發者。php
JavaScript
極速發展的今天,回調地獄所產生的問題已不復存在。實際開發過程當中咱們應當儘可能避免使用回調函數,除非爲了遵照代碼庫規則或是維護性能。而解決回調地獄的一個經常使用方法爲 Promise
,但在代碼量較多時使用會拔苗助長。因而提出了 async / await
,使代碼結構更加清晰明瞭,便於閱讀和維護。通常而言,能夠 await
任何 Promise
以防止正使用的庫的返回值爲 Promise
,也就是說 async/await
是 Promise
的語法糖,並且使用方法也十分簡單:在函數前加 async
。下面是一個簡單的例子: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()
複製代碼
await 只能使用在 async 函數中,不能用於全局做用域。 前端
async/await
是 ES2017 中引入的,使用時請進行轉換。java
當咱們進行異步調用並得到返回值時,一般指望直接獲取多個數據集,而且分別操做每一個數據集。所以有了如下方式:react
假設頁面上要展現 Pokemon 數據,能夠經過 axios
獲取它們的詳細信息,咱們所指望的是在獲得返回值時當即更新頁面中的全部數據,而不是等全部調用完成後才進行更新。webpack
咱們可使用 for...of
解決上述問題。 首先循環遍歷數組,並在每一個循環內執行異步代碼,當全部調用都成功時跳出循環。須要注意的是,這種方法雖然會對性能產生一些影響,但也不乏是一個很好的方法。ios
如下是一個例子:git
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)
複製代碼
能夠將這些例子複製粘貼到編輯器中調試運行。github
譯者注:除了循環自己帶來的性能問題以外,在使用
async/await
處理異步請求時也會對性能形成影響:若是使用過多await
語句,並且候這些語句並不須要依賴於以前的語句,則會產生async/await
地獄,影響性能。
若是想要並行獲取全部的 Pokemon,咱們可使用 Promise.all
方法來 await
全部 Promise
:
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+
引入的,使用時請進行轉換。
回到上個例子:
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
複製代碼
ES6
引入瞭解構賦值和默認值,使用時請進行轉換。
當咱們使用默認值時,一般要對現有值進行一系列判斷,這種方法使代碼變得異常繁瑣,而如今咱們能夠真值(Truthy
)和虛值(Falsy
)的方式來改進它,不只能夠節省代碼量,還令人更加信服。
如下是以前的作法:
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(...)
}
複製代碼
如下爲 Falsy
和 Truthy
的概念:
Falsy
0
false
undefined
null
NaN
Truthy
使用真值和虛值時沒有確切的比較方式,這相似於咱們進行比較時常使用雙等號 ==
而不是三等號 ===
。通常而言,這二者的斷定方式相同,但在某些狀況下也會遇到一些錯誤,對我來講主要爲數字 0
。
邏輯運算符和三元運算符主要用於精簡代碼,有助於保持代碼整潔度,但當他們造成運算鏈時會顯得雜亂。
邏輯運算符:和(&&
)、或(||
),通常用於比較兩個表達式,返回值爲: true
、false
或着它的匹配值。以下例:
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
複製代碼
咱們能夠將邏輯運算符與真值和虛值的相關知識結合起來。
若是有表達式 A
和 B
,針對兩種邏輯運算符,有如下規則:
A && B
: 當 A
爲 false
時則直接返回 A
的值 ;不然返回 B
的值。A || B
: 當 A
爲 true
時則直接返回 A
的值 ;不然返回 B
的值。譯者注:上述規則爲邏輯運算中的短路現象。
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
複製代碼
三元運算符與邏輯運算符很是類似,但有由三個部分組成:
例如:
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 eveing
複製代碼
當訪問某個嵌套對象的屬性時,因爲不能肯定目標對象或者屬性性是否存在,而須要進行一系列判斷:
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
複製代碼
譯者注:自判斷連接: 檢查一個對象上面是否存在某屬性。
出現緣由:調用某Object
屬性鏈中的某個屬性時,若是該屬性不存在,會致使Cannot read property xxx of undefined
錯誤。因而自判斷連接?.
出現。
使用方式:obj?.a?.b?.c
。依次對代碼中的屬性進行判斷,若是爲null
或者undefined
時,結束調用,返回undefined
。
目前,自判斷連接還未歸入官方規範中,只處於第一階段的實驗特性。您須要在
babelrc
中添加@ babel / plugin-proposal-optional-chaining
後方可以使用它。
JavaScript
中常常會用到綁定(bind
)。ES6
規範中箭頭函數的引入,使 JavaScript
開發人員有了一種將函數自動綁定到執行上下文中的經常使用方法,同時這種方法很是重要。
因爲 JavaScript
中的類方法有特定的調用方式,所以當咱們首次聲明一個類時不能使用箭頭函數,所以須要在其餘位置進行函數綁定,好比在構造函數中(以 React.js
爲例)。工做當中我老是先定義類方法再對其進行綁定,這種方法很是繁瑣且容易出錯。但若是使用 class
語法,咱們能夠經過箭頭函數自動綁定它。如下是綁定 _increaseCount
的例子:
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 })
}
}
複製代碼
目前,類屬性還未歸入官方規範中,只處於第三階段的實驗特性。您須要在
babelrc
中添加@ babel / plugin-proposal-class-properties
後方可以使用。
做爲前端開發人員,保證會有打包項目或着轉換代碼的需求,對此,webpack 已經在好久以前提出先關規範了。第一次使用 webpack v1.0 時,我花了很長時間進行配置,雖然最終運行成功,但整個過程很是痛苦,並且成功後的我變得畏手畏腳,生怕破壞以前的配置。直到幾個月前,ParcelJS
的發現使我心情大好,在提供開箱即用功能的同時,它還實現了按需配置,也能夠支持相似於 webpack 或 babel 的插件系統,最重要的是它的速度極快。
譯者注:ParcelJS 官網顯示,parcelJS 的打包速度比 webpack 快 2 倍以上。
這是一個很是有趣的話題,關於它我有不少的想法。對於 CSS
,不少人更傾向於使用相似於 BootStrap 這樣的組件庫。而對於 JavaScript
,仍然有人調用 jQuery
或者其餘庫來實現驗證、滑塊等功能。首先不否定使用各類庫的好處,但仍是強烈建議能夠親手實現這些功能,而不是盲目地安裝 npm 包。當整個團隊正構建一個相似於 moment.js 或 react-datepicker 的大型庫(甚至框架)時,你不必親手實現它,但能夠封裝爲屬於本身的組件庫,並且在實現組件庫的同時,您能夠:
直接使用 npm 包是固然很是容易,但若是想要實現某些 npm 包中不具有的功能時則會須要更多的時間:若是軟件沒有按預期正常工做,或者要將其轉換爲另外一個軟件包,您將會花費更多時間來了解其 API 的配置方式。所以,您能夠爲本身量身定作一套數據本身的組件庫。
關於做者:Lukas Gisder-Dubé 組件並領導了一家初創公司,期間創建了本身的技術團隊,並任職 CTO 一年半。 離開創業公司後,在 Ironhack 擔任首席講師。現在在柏林正創建一家創業諮詢公司。查看 dube.io 以瞭解更多信息。