原文自工程师Enmanuel Durán博客,传送门

最近(或者不是最近,这完全取决于您什么时候阅读这边文章),我正在跟我的团队伙伴讨论如何去处理这种需要根据不同的值去处理不同的情况的方法,通常对于这种情况下,人们喜欢使用switch语句或者使用很多if搭配else if条件。在本文中我将重点介绍第三种方式(我更为喜欢的方法),即使用对象进行快速地查找。

switch 语句

switch语句允许我们根据传递的表达式的值来执行表达式并执行某些特定的操作,通常当你学习编写代码和算法时,你会发现可以将它专门用于多种值的情况,你开始使用它,它看起来很好,你很快意识到它给了你很大的自由,耶!但是要小心,自由度越大责任感也就越大。

让我们快速了解一下典型的switch语句是怎么样的:

switch (expression) {case x: {/* Your code here */break;}case y: {/* Your code here */break;}default: {/* Your code here */}
}

很好,现在有一些你可能不知道需要注意的事情:

可选的关键字break

break关键字允许我们在满足条件时停止执行块。如果不将break关键字添加到switch语句,则不会抛出错误。如果我们不小心忘记break的话,可能意味着在执行代码的时候你甚至不知道代码已经正在执行中了,这还会在调试问题时增加实现结果的的不一致性、突变、内存泄漏和复杂度等问题。我们来看看这个问题的一种表示形式:

switch ('first') {case 'first': {console.log('first case');}case 'second': {console.log('second case');}case 'third': {console.log('third case');break;}default: {console.log('infinite');}
}

如果你在控制台中执行这段代码,你会看到输出是

firt case
second case
third case

switch语句在第二种和第三种情况下也会执行,即使第一种情况已经是正确的,然后它在第三种情况块中找到关键字break并停止执行,控制台中没有警告或错误让你知道它,这会让你认为这是预期的行为。

每种情况下的大括号都不是强制的

在javascript中大括号代表着代码块,因为自ECMAscript 2015我们可以使用关键字声明块编译变量,如const或let(但对于switch来说并不是很好),因为大括号不是强制性的,重复声明会导致错误变量,让我们看看当我们执行下面的代码时会发生什么:

switch ('second') {case 'first':let position = 'first';console.log(position);break;case 'second':let position = 'second';console.log(position);break;default:console.log('infinite');
}

我们会得到:

Uncaught SyntaxError: Identifier 'position' has already been declared

这里将会返回一个错误,因为变量position已经在第一种情况下声明过了,并且由于它没有大括号,所以在第二种情况下尝试声明它,它已经存在了。

现在想象使用带有不一致break关键字和大括号的switch语句时会发生什么事:

switch ('first') {case 'first':let position = 'first';console.log(position);case 'second':console.log(`second has access to ${position}`);position = 'second';console.log(position);default:console.log('infinite');
}

控制台将输出以下内容:

first
second has access to first
second
infinite

试想一下,由此而引起的错误和突变是如此之多,其可能性是无穷无尽的……不管怎样,switch语句已经讲够了,我们来这里是为了讨论一种不同的方法,我们来这里是为了讨论对象。

更安全查找的对象

对象查找速度很快,随着它们的大小增长它们也会更快,它们也允许我们将数据表示为对于条件执行非常有用的键值对。

使用字符串

让我们从简单的switch示例开始,让我们假设我们需要有条件地保存和返回一个字符串的情景,并使用我们的对象:

const getPosition = position => {const positions = {first: 'first',second: 'second',third: 'third',default: 'infinite'};return positions[position] || positions.default;
};const position = getPosition('first'); // Returns 'first'
const otherValue = getPosition('fourth'); // Returns 'infinite'

这可以做同样类型的工作,如果你想进一步的压缩简化代码,我们可以利用箭头函数:

const getPosition = position =>({first: 'first',second: 'second',third: 'third'}[position] || 'infinite');const positionValue = getPosition('first'); // Returns 'first'
const otherValue = getPosition('fourth'); // Returns 'infinite'

这与前面的实现完全相同,我们在更少的代码行中实现了更紧凑的解决方案。

现在让我们更实际一点,不是我们写的所有条件都会返回简单的字符串,其中很多会返回布尔值,执行函数等等。

使用布尔值

我喜欢创建返回类型一致的值的函数,但是,由于javascript是动态类型语言,因此可能存在函数可能返回动态类型的情况,因此我将在此示例中考虑这一点,如果找不到键,我将创建一个返回布尔值,未定义或字符串的函数。

const isNotOpenSource = language =>({vscode: false,sublimetext: true,neovim: false,fakeEditor: undefined}[language] || 'unknown');const sublimeState = isNotOpenSource('sublimetext'); // Returns true

看起来不错,对吧?别急,好像我们有一个问题......如果我们调用带有参数的函数,会发生什么'vscode'或fakeEditor不是?嗯,让我们来看看:

  1. 它会寻找对象中的键。
  2. 它会看到vscode键的值是false。
  3. 它会试图返回false,但因为false || 'unknown'是unknown,我们最终会返回一个不正确的值。

对于key为fakeEditor也会有同样的问题

Oh no, 好吧,不要惊慌,让我们来解决这个问题:

const isNotOpenSource = editor => {const editors = {vscode: false,sublimetext: true,neovim: false,fakeEditor: undefined,default: 'unknown'};return editor in editors ? editors[editor] : editors.default;
};const codeState = isNotOpenSource('vscode'); // Returns false
const fakeEditorState = isNotOpenSource('fakeEditor'); // Returns undefined
const sublimeState = isNotOpenSource('sublimetext'); // Returns true
const webstormState = isNotOpenSource('webstorm'); // Returns 'unknown'

这就解决了问题,但是......我希望你们问自己一件事:这真的是问题所在吗?我认为我们应该更关心为什么我们需要一个返回布尔值,未定义值或字符串的函数,这里存在严重的不一致性,无论如何,对于这样一个非常棘手的情况这也只是一个可能的解决方案。

使用函数

我们继续讲函数,通常我们会发现我们需要根据参数来执行一个函数,假设我们需要根据输入的类型来解析一些输入值,如果解析器没有注册,我们只返回值:

const getParsedInputValue = type => {const emailParser = email => `email,  ${email}`;const passwordParser = password => `password, ${password}`;const birthdateParser = date => `date , ${date}`;const parsers = {email: emailParser,password: passwordParser,birthdate: birthdateParser,default: value => value};return parsers[type] || parsers.default;
};// We select the parser with the type and then passed the dynamic value to parse
const parsedEmail = getParsedInputValue('email')('myemail@gmail.com'); // Returns email, myemail@gmail.com
const parsedName = getParsedInputValue('name')('Enmanuel'); // Returns 'Enmanuel'

如果我们有一个类似的函数返回另一个函数但这次没有参数,我们可以改进代码,以便在调用第一个函数时直接返回,如:

const getValue = type => {const email = () => 'myemail@gmail.com';const password = () => '12345';const parsers = {email,password,default: () => 'default'};return (parsers[type] || parsers.default)(); // we immediately invoke the function here
};const emailValue = getValue('email'); // Returns myemail@gmail.com
const passwordValue = getValue('name'); // Returns default

通用代码块

Switch语句允许我们为多个条件定义公共代码块。

switch (editor) {case 'atom':case 'sublime':case 'vscode':return 'It is a code editor';break;case 'webstorm':case 'pycharm':return 'It is an IDE';break;default:return 'unknown';
}

我们如何使用对象来处理它?我们可以在下一个方面做到这一点:

const getEditorType = type => {const itsCodeEditor = () => 'It is a code editor';const itsIDE = () => 'It is an IDE';const editors = {atom: itsCodeEditor,sublime: itsCodeEditor,vscode: itsCodeEditor,webstorm: itsIDE,pycharm: itsIDE,default: () => 'unknown'};return (editors[type] || editors.default)();
};const vscodeType = getEditorType('vscode'); 

现在我们有一种方法:

  1. 更有条理
  2. 更易拓展
  3. 更容易维护
  4. 更容易测试
  5. 更安全并且副作用和风险更小

注意事项

正如预期的那样,所有的方法都有其缺点,这一个也不例外。

  1. 由于我们正在使用对象,所以我们将占用内存中的一些临时空间来存储它们,当定义对象的作用域不再可访问时,这个空间将被垃圾收集器释放。
  2. 当没有太多情况需要处理时,对象方法可能比switch语句的速度要慢,这可能是因为我们正在创建一个数据结构,然后接收一个键,然而在switch中,我们只是检查值并返回值。

结论

本文不打算改变你的编码风格或让你停止使用switch语句,它只是试图提高你对switch语句的认识,以便它可以正确使用,并开放你的思想探索新的替代方案,在这种情况下,我已经分享了我喜欢使用的方法,但还有更多,例如,你可能想看一个称为模式匹配的ES6提案,如果你不喜欢它,你可以继续探索。

好的开发未来,就是这样,我希望你喜欢这篇文章,如果你这样做,你可能会喜欢这篇关于工厂模式的文章。此外,不要忘记分享和点赞,你可以在twitter上找到我或通过我的电子邮件duranenmanuel@gmail.com联系我,下一个见。

阅读EnmaScript.com上发布的原始文章

译者总结

本文介绍了一种使用对象去代替我们之前用switch和繁琐的if else语句的方法。其实,很多情况下我们可以利用对象与其他组合搭配写出更为高效或可维护的代码。当然,如何去灵活地使用对象去处理一些对应的情况,还是靠我们自己。好的,这篇就总结到这了,不知道对你们有什么启发。相信会给到一些帮助给读者,我们可不是一个只会if else的工程师,哈哈~

【译】为什么我更喜欢对象而不是switch语句相关推荐

  1. 「每周译Go」如何在 Go 中编写 Switch 语句

    目录 在 Go 中导入包 理解 Go 中包的可见性 如何在 Go 中编写条件语句 如何在 Go 中编写 Switch 语句 如何在 Go 中构造 for 循环 在循环中使用 Break 和 Conti ...

  2. linux命令为什么这么快,为什么这么多Linux用户更喜欢命令行而不是GUI?

    为什么这么多 Linux 用户更喜欢 CLI 而非 GUI? 上次我在 Reddit 关注该问题时,遇到了一些有帮助的投稿: "处于相同的原因我更喜欢谈论指指点点和七嘴八舌. 可以很好的传达 ...

  3. 保持函数依赖的模式分解可以减轻或解决什么_为什么我更喜欢函数式编程?

    作者 | Mario Morgenthum 译者 | 平川 编辑 | 陈思 AI 前线导读:在学习 Haskell 之前,作者一直使用主流语言,如 Java.C 和 C++--现在他仍然喜欢它们.那么 ...

  4. 纸上原型设计 VS 桌面原型工具设计,你更喜欢谁?

    2019独角兽企业重金招聘Python工程师标准>>> 纸上原型设计,作为传统的原型设计方式,简单快速,成本低廉,为大部分设计师所喜爱.而桌面原型工具设计,作为伴随电脑科技发展而出现 ...

  5. (转)javascript 杂谈之哪种写法你更喜欢?

    原文地址:http://www.cnblogs.com/baochuan/archive/2012/04/30/2473771.html 思维导图 介绍 老是在写js,你平时是怎么写你的js呢?更喜欢 ...

  6. C++/Python/Java/C,四大语言对比,你更喜欢哪种?

    现如今,互联网时代已经是风生水起,IT技术人才更是层出不穷.但学习在精不在多,总要有一方面精通才是自己的资本.面对众多的编程语言,Java.C语言.C++.Python等编程,你更喜欢哪种? 虽说C语 ...

  7. 了解MVP(最小可行产品) - 以及为什么我更喜欢最早的可测试/可用/可爱

    几年前,我画了这张照片并开始在关于敏捷和精益开发的各种演示中使用它: 从那时起,绘画已经病毒化!在文章和演示文稿中,甚至在一本书中都可以显示出来(Jeff Patton的" 用户故事映射 & ...

  8. 刀片式服务器与虚拟机,为什么人们在开发虚拟主机时更喜欢刀片服务器?

    服务器制造商正在不断开发刀片技术,因此刀片服务器的处理器性能和内存容量已达到10年前的超级计算机水平.毫无疑问,刀片服务器曾经实现了"事半功倍"的承诺,但现在需要重新考虑这个问题. ...

  9. 六种流行的语言大餐---C、C++、python、Java、php、C#你更喜欢哪一个呢?

    引言 鉴于五一期间超大的人流量,LZ思来想去,最终还是选择蜗居在自己的出租屋.无聊之际,当然不能忘了做点什么事情,于是LZ就研究了一下几种语言的皮毛,在这里献丑一翻,希望各位猿友莫要见笑. 不过说来也 ...

最新文章

  1. 【生活随想】实习结束以及开始校园招聘
  2. SpringCache与redis集成,优雅的缓存解决方案
  3. mysql 内连接查询慢_MySQL慢查询有2个内连接
  4. 爱情第七课,被爱的秘密
  5. nginx php动态编译加载模块.
  6. AI的下半场怎么走,这朵云知道
  7. 阿里云数据库产品HybridDB简介——OLAP数据库,支持行列混合存储,为用户提供基于开源 OLTP、OLAP、BigData 生态的一站式解决方案...
  8. 强大的DataGrid组件[7]_自定义DataGrid——Silverlight学习笔记[15]
  9. 垃圾回收机制和菜单栏工具栏
  10. Appium+Python移动端 实战——教你如何xpath定位自动化测试
  11. 【机房收费系统】---结账
  12. 获取网关IP和MAC 的VB源码
  13. 通过镜像快速搭建本地yum源
  14. Java内存五大区_一:jvm的五大内存区(内存结构)
  15. python3-pwntools教程_CTF PWN工具篇1
  16. 国内银行卡BIN号速查简表
  17. 2021下半年河南郑州普通话测试报名入口
  18. 计算机图片怎样存在桌面上,电脑桌面上怎么放照片
  19. 电信话务查询真的那么难?
  20. 展示一下香蕉派路由Android系统

热门文章

  1. django python3.6_Django+mysql+python3.6.5 Windows
  2. 全虚拟化和半虚拟化的区别 cpu的ring0~ring3又是什么概念?
  3. MJRefresh-简单使用
  4. 配置 tsconfig.json
  5. [deviceone开发]-do_SlideListView的简单示例
  6. 花点时间了解消息,句柄和窗口
  7. android中AsyncTask和Handler对比
  8. Google, 请不要离开我们!
  9. url模糊匹配优化_企业必备的网站SEO优化解决方案
  10. fastreport 直接调网络打印机_为什么UV打印机不能打印凹凸不平的材料?