又一年过去了,JavaScript 发生了很多变化。 而且,即使已经是 2019 年了,仍然需要一些建议来帮助您编写干净、整洁、有效且可扩展的代码。
以下为译文:
以下 9 个技巧可帮助您成为更好的开发人员。
1. 异步/等待
如果您仍在与反弹陷阱作斗争,您应该快速放弃这个 2014 年的代码。 除非绝对必要(例如,库需要它,或者出于性能原因),否则不要使用反弹。 Promise 也很好,但是当代码大小增加时,它们往往会有点尴尬。
我的解决方案是async/await,这使得阅读代码更容易,代码更干净。 事实上,Javascript中任何Promise都可以await,只要你使用的库可以返回Promise,你就可以await它。 事实上,async/await只不过是promise的语法糖。 为了让代码正确运行,只需要在函数后面添加async即可。
这是一个反例:
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,并且await只能用在async函数中。 据悉,async/await是在ES2017中引入的,因此不需要编译(转译)代码。
2. 异步控制流程
很多时候jquery 为空判断,您需要获取多个数据集并对每个数据集进行一些处理,或者在所有异步调用返回后执行任务。
为了...的
假设网页上有一些神奇宝贝,我们需要获取每一个神奇宝贝的详细信息。 我们迫不及待地等待所有呼叫结束,因为我们不知道有多少个呼叫。 我们希望得到一部分数据并立即更新数据集。 这时候我们可以使用for...of来循环一个链表,然后在内部添加一个异步代码块,但是这样会造成阻塞,直到所有调用结束。 需要注意的是,这样做可能会导致性能困难,但这也是一种方法。
示例如下:
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)
这种例子其实是可以运行的,你可以自己复制粘贴到你喜欢的代码沙箱工具中。
承诺。 全部
如何同时获得所有神奇宝贝? 我们可以等待所有的 Promise,只需使用 Promise.all:
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)
ES6+中引用了for...of和Promise.all,因此需要编译代码。
3. 解释和默认值
我们现在回到上面的例子:
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(...)
另一个小技巧是重构时设置默认值。 这确保了变量永远不会未定义,因此无需手动检查变量。
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+ 中引入了解释和默认值,因此代码需要编译。
4.真假值
当使用默认值时,通常需要检测值的存在。 另外,您可以直接使用 true 和 false 值。 这样可以改进代码,节省大量字符,使代码更加流畅。 我经常听到人们写:
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(...) }
要真正理解此类句子的好处,您必须了解真值和假值是什么。 以下是部分摘要:
假值
真实价值
测试 true 或 false 值时,无需显式编写比较,相当于使用双等号 == 而不是三等号 ===。 一般来说,这些用法的行为符合预期,但可能会遇到错误。 例如,我最常遇到的 0 号 bug 就是 bug。
该运算符还用于减少代码,节省宝贵的代码行。 通常有很多工具可以保持代码干净整洁,但这些工具也会导致混乱,尤其是在更改它们时。
逻辑运算符
逻辑运算符组合两个表达式并返回 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
根据我们在上一节中了解的 true 和 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
三元运算符
三元运算符就像一个逻辑表达式,但它由三个部分组成:
下面是一个反例:
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、连锁经营
您遇到过这个问题吗? 访问嵌套对象的属性时,无法提前判断该对象的属性是否存在? 可能需要写这样的代码:
let data if(myObj && myObj.firstProp && myObj.firstProp.secondProp && myObj.firstProp.secondProp.actualData) data = myObj.firstProp.secondProp.actualData
这段代码很荒谬,我们有更好的方法,至少是建议的方法(下面介绍如何启用它)。 这种方法称为可选链,其用法如下:
const data = myObj?.firstProp?.secondProp?.actualData
通过这种方式检测嵌套属性非常流畅,代码看起来也更干净。
目前,可选链不是官方标准的一部分,但它是第一阶段的实验功能。 需要在 babelrc 中添加 @babel/plugin-proposal-optional-chaining 来启用它。
7. 类属性和绑定
JavaScript 中的函数绑定是一项非常常见的任务。 由于 ES6 标准引入了箭头函数jquery 为空判断,我们现在可以以定义的方式手动绑定函数 - 这非常有用,并且被当今的 JavaScript 开发人员使用。 当类第一次出现时,没有办法使用箭头函数,因为类需要以特殊的方式定义。 我们需要在某个地方进行绑定,例如在构造函数中(这是在 React.js 中执行此操作的最佳方法)。
我讨厌需要先定义类方法然后绑定方法的过程,但现在你可以通过箭头函数手动绑定。 箭头函数现在可以直接在类中使用。
下面是一个反例,其中绑定了_increaseCount:
class Counter extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return() } _increaseCount = () => { this.setState({ count: this.state.count + 1 }) } }{this.state.count}
目前,类属性不是官方标准的一部分,而是第三阶段的实验功能。 您必须在 babelrc 中添加 @babel/plugin-proposal-class-properties 才能使用它。
8. 使用包裹
作为后端开发人员,您肯定会遇到打包和编译代码的问题。
长期以来,实践中的标准是 webpack。 我从 webpack 版本 1 开始,不断更改和尝试各种配置选项是一件很痛苦的事情,我花了无数的时间试图让它工作。 一旦完成,我就再也不会碰它,以免不小心弄坏了东西。 几个月后我遇到了parcel,终于松了一口气。 它可以开箱即用,几乎无需配置,但您仍然可以在需要时进行更改。 它还支持插件,类似于 webpack 和 babel,但速度非常快。
如果您不知道包裹,我建议您尝试一下。