为什么你的 JavaScript 代码如此冗长?!
又一年过去了,JavaScript发生了许多变化。但是,即使是2019年了,还是需要给一些帮助你编写干净、整洁、有效、且具有扩展性的代码建议。
作者 | Lucas Gisder-Dubé
译者 | 弯月
责编 | 郭芮
出品 | CSDN(ID:CSDNnews)
以下为译文:
下面是让你成为更好的开发者的9条建议。
async / await
如果你还在为回调陷阱烦恼不已,那么就应该赶快扔掉这些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中引入的,所以务必要对代码进行编译(transpile)。
异步控制流
许多时候需要获取多个数据集并在每个数据集上做一些处理,或者在所有异步调用都返回之后执行某项任务。
for...of
假设网页上有一些精灵宝可梦,我们需要获取每一只的详细信息。我们不能等待所有调用结束,因为我们不知道一共有多少只。我们希望能在获取一部分数据之后立即更新数据集,这时候就可以使用for...of在一个数组上进行循环,然后在内部加入async的代码块,但这样做会造成阻塞,直到所有调用结束。一定要注意,这样做有可能会造成性能瓶颈,但这样做也不失为一种办法。
例子如下:
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.all
怎样才能并行获取所有宝可梦呢?我们可以await所有的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)
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(...)
另一个小技巧就是在解构时制定默认值。这样能保证变量永远不会为undefine,因此就不需要手工检查变量了。
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()) // 3console.log(calculate({type: 'division'})) // 0.5console.log(calculate({operands: [2, 3, 4], type: 'multiplication'})) // 24
第一眼看上去这个例子可能不太容易理解,但多花些时间研究下是有好处的。当我们不给函数传递参数时,就会使用默认值。如果给函数传递参数,那么不存在的参数就会使用默认值。
解构和默认值是在ES6+中引入的,所以代码需要编译。
真值和假值
在使用默认值时,经常需要检查存在的值。但是,你还可以直接使用真值和假值。这样能改善代码并节省好多字符,使代码更加流畅。我经常看到人们这样写:
if(myBool === true) { console.log(...)}// ORif(myString.length > 0) { console.log(...)}// ORif(isNaN(myNumber)) { console.log(...)}
这些代码可以缩写成:
if(myBool) { console.log(...)}// ORif(myString) { console.log(...)}// ORif(!myNumber) { console.log(...)}
要真正理解这些语句的好处,你必须要理解真值和假值都是什么。下面是部分摘要:
假值
长度为0的字符串
数字0
false
undefined
null
NaN
真值
空数组
空对象
任何其他东西
当检查真值或假值时,不需要明确写出比较,这相当于使用双等号 == 而不是三等号 ===。一般来说,这种用法的行为与预想是一致的,但有可能会遇到bug。比如,我最常遇到但就是有关数字0的bug。
逻辑运算符和三元运算符
这些运算符也是用来缩减代码的,节省下宝贵的代码行数。经常有许多工具可以保持代码干净整洁,但这些工具也会造成混乱,特别是在改变它们时。
逻辑运算符
逻辑运算符可以组合两个表达式,并返回true或false,或者匹配的值。常用的有&&,意思是“与”,还有 || 意思是“或”。我们来看看:
console.log(true && true) // trueconsole.log(false && true) // falseconsole.log(true && false) // falseconsole.log(false && false) // falseconsole.log(true || true) // trueconsole.log(true || false) // trueconsole.log(false || true) // trueconsole.log(false || false) // false
根据上一部分关于真值和假值的知识,我们可以将逻辑运算符组合起来。在使用逻辑运算符时,会使用以下规则:
&& :返回第一个值为假的表达式的值。如果不存在,则返回最后一个值为真的值。
|| :返回第一个值为假的表达式的值。如果不存在,则返回最后一个值为假的值。
console.log(0 && {a: 1}) // 0console.log(false && 'a') // falseconsole.log('2' && 5) // 5console.log([] || false) // []console.log(NaN || null) // nullconsole.log(true || 'a') // true
三元运算符
三元运算符很像逻辑表达式,但它由三个部分组成:
比较部分,返回假值或真值;
第一个值,如果比较为真;
第二个值,如果比较为假。
下面是例子:
const lang = 'German'console.log(lang === 'German' ? 'Hallo' : 'Hello') // Halloconsole.log(lang ? 'Ja' : 'Yes') // Jaconsole.log(lang === 'French' ? 'Bon soir' : 'Good evening') // Good evening
链式操作
你遇到过这个问题吗?在访问嵌套对象的属性时,无法事先确定对象的属性是否存在?可能不得不写这样的代码:
let dataif(myObj && myObj.firstProp && myObj.firstProp.secondProp && myObj.firstProp.secondProp.actualData) data = myObj.firstProp.secondProp.actualData
这段代码很荒谬,我们还有更好的办法,至少是在建议中的办法(下面说了怎样启用该办法)。这个办法称为optional chaining,用法如下:
const data = myObj?.firstProp?.secondProp?.actualData
用这个方法检查嵌套属性非常流畅,代码也能变得更干净。
目前,optional chaining还不是官方标准的一部分,但它是个stage-1的实验性功能。需要在babelrc中加入@babel/plugin-proposal-optional-chaining来启用它。
类属性和绑定
JavaScript中的函数绑定是个非常常见的任务。由于ES6标准引入了箭头函数,我们现在可以自动地用定义的形式绑定函数——这方法非常好用,现在的JavaScript开发者都在用它。之前类刚刚出现时是没办法使用箭头函数的,因为类需要用某种特殊的方式来定义。我们需要在某个地方进行绑定,例如在构造函数里(在React.js中最好这样做)。
我很讨厌需要先定义类方法再绑定方法的流程,不过现在可以通过箭头函数进行自动绑定。箭头函数现在可以直接在类中使用。
下面是个例子,其中的_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 }) }}
目前,类属性不是官方标准的一部分,但是个stage-3的实验性功能。必须在babelrc中添加@babel/plugin-proposal-class-properties才能使用它。
使用parcel
作为前端开发者,你肯定会遇到打包和编译代码的问题。
长时间以来,实践中的标准是webpack。我最初用的是webpack版本1,当时用起来很痛苦,需要不断修改尝试各种配置选项,我在上面花了无数个小时想办法让它工作。一旦弄好我就绝不会再碰它,以免不小心破坏什么。几个月之后我遇到了parcel,总算松了口气。它几乎可以不加任何配置拿来即用,但你依然可以在需要的时候进行改变。它还支持插件,类似于webpack和babel,但非常快。
如果你不知道parcel,我建议你一定要试试。
自己写更多代码
这一条很有意思,这个话题我已经讨论过很多次了。
即使是CSS,许多人也喜欢用现成的库,比如bootstrap。至于JavaScript,现在还有很多人在用jQuery以及各种小型库进行表单验证、跑马灯等等。虽然使用库天经地义,但我强烈建议你自己写更多的代码,而不是依赖于安装各种npm包。当然,大型的库(甚至框架)需要整个团队去构建,如moment.js或react-dateicker,自己写是不现实的。
但是,其他的大部分东西都可以自己写。这样能带来三个好处:
你清楚地知道代码的内容;
在某个点上你开始真正理解编程,知道内部的工作原理;
可以防止代码膨胀。
最初直接使用npm包很方便。自己实现一些功能会花很多时间。但是,如果安装的包并不能正常工作,而需要换别的方法,就得花更多的时间去阅读其API。而在自己实现时,你可以为项目100%地量身定做。
原文:https://levelup.gitconnected.com/9-tricks-for-kickass-javascript-developers-in-2019-eb01dd3def2a
作者:Lucas Gisder-Dubé,曾联合创立过一家创业公司,并担任CTO一年半的时间。离开创业公司后,他在Ironhack作为讲师给别人讲编程。
本文为 CSDN 翻译,如需转载,请注明来源出处。
热 文 推 荐
春运车票为谁“秒空”?第三方软件的困与危
编程 25 年后,现实将我打回菜鸟程序员的起点
前方 Bug 出没?盘他!
☞“离开360时,它只给了我一块钱”
☞ 原子互换:一统公链江湖的神来之笔
☞ AI找Bug,一键快速预测
☞ 5G大规模商用来临之前,你必须知道的几个知识点
☞ 女程序员:我敲代码养家,老公负责貌美如花!
print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"
喜欢就点击“好看”吧!
为什么你的 JavaScript 代码如此冗长?!相关推荐
- 以优美方式编写JavaScript代码
英文原文:CoffeeScript: The beautiful way to write JavaScript 我用 JavaScript 编程很多年了,写了大量的 JavaScript 代码,即便 ...
- JavaScript进阶:如何写出优雅的JavaScript代码
目录 一.可维护性代码 二.编码规范-可读性 三.变量和函数命名 四.松散耦合 1.解耦HTML和JavaScript 2.解耦CSS和JavaScript 3.解耦应用程序逻辑和事件处理程序 五.编 ...
- 翻译-高质量JavaScript代码书写基本要点(转载)
by zhangxinxu from http://www.zhangxinxu.com 本文地址:http://www.zhangxinxu.com/wordpress/?p=1173 原文作者:S ...
- javascript 代码_如何使您JavaScript代码保持简单并提高其可读性
javascript 代码 by Leonardo Lima 莱昂纳多·利马(Leonardo Lima) 如何使您JavaScript代码保持简单并提高其可读性 (How to keep your ...
- javascript 代码_代码简介:2016年JavaScript的现状
javascript 代码 Here are three stories we published this week that are worth your time: 这是我们本周发布的三个值得您 ...
- js如何运行python代码_python中执行javascript代码
python中执行javascript代码: 1.安装相应的库,我使用的是PyV8 2.import PyV8 ctxt = PyV8.JSContext() ctxt.enter() func = ...
- 优化javaScript代码,提高执行效率
今天看完书,总结了一下可以如何优化 JavaScript . 1.合并js文件 为优化性能,可以把多个js文件(css文件也可以)合并成极少数大文件.跟十个5k的js文件相比,合并成一个50k的文件更 ...
- easyui treegrid 获取新添加行inserted_18行JavaScript代码构建一个倒数计时器
有时候,你会需要构建一个JavaScript倒计时时钟.你可能会有一个活动.一个销售.一个促销或一个游戏.你可以用原生的JavaScript构建一个时钟,而不是去找一个插件.尽管有很多很棒的时钟插件, ...
- 如何优雅的编写 JavaScript 代码
几乎每个大一点公司都有一个"运行时间长,维护的工程师换了一批又一批"的项目,如果参与到这样的项目中来,大部分人只有一个感觉--"climb the shit mounta ...
最新文章
- 泰坦尼克号数据集_机器学习(入门)--Kaggle项目之泰坦尼克号
- 《LeetCode力扣练习》剑指 Offer 10- II. 青蛙跳台阶问题 Java
- linux下的last以及lastb命令
- dede调用头条非头条
- Python中定义函数的三种形式
- 【转】人工智能-1.2.2 神经网络是如何进行预测的
- mysql如何进行分组操作的_mysql group by 对多个字段进行分组操作
- android api文档_【粉丝投稿】无需额外注解的 SpringBoot API文档生成工具
- 图:活动现场双屏管理系统V3-多线程抽奖版软件,完美升级收工!历时3个月,艰辛坎坷...
- 在Windows Server 2008下安装Oracle 10g出现未知错误
- yudian温控表a1温度怎么补偿_贴片电容怎么确定型号
- 2019年注册测绘师备考历程
- bdd java_二元判断图BDD及其JAVA实现的应用与研究
- php矢量瓦片,【教你一招】张海平:如何将小范围在线地图切片数据转换为GIS矢量数据?...
- 自定义拍照时 拍照界面_当生活中拍照不知道摆什么姿势时,可以试试动漫中这些动作...
- 生活手机必备5款APP,一用就会上瘾,简直就是生活中的好帮手
- VUE酒店日期选择,时间段选择插件vue-mobile-calendar使用
- 计算机打开程序乱码,打开软件乱码怎么解决,详解win7电脑打开软件乱码的解决方法...
- 树和二叉树知识点思维导图
- unity上传头像_unity通过http上传图片到服务器
热门文章
- 查看pytorch和匹配的CUDA版本
- ant design Cascader 实现联动省市区数据
- java中将数字颠倒的工具类,java开发中常用的数字工具类
- 信息泄露案件_圆通回应运单信息泄露案件:系主动报案,涉4万余条敏感信息...
- AI分析猪叫声中的情绪,“贾维斯”“大白”会不会照进现实?
- 基于Flink CDC打通数据实时入湖
- 信通院 DevOps 新标准评估结果发布:腾讯获评唯一卓越级
- 程序员的自我救赎,GitHub 摸鱼神器一览
- 你正在学 Web 自动化测试?Selenium 基本操作你了解嘛? | 原力计划
- 首提“智能X效应”,英特尔携手产业加速智能变革