JavaScript 的 switch 有四样写法,你都知道哪些?
JavaScript 的 switch 语句只有一种写法。其他的写法,if 分支写法可以算一种,switch 分支写法可以算第二种,第三种是使用策略模式,如果要把条件运算符也算上的话,嗯,刚好四种。
switch一般写法
switch 的写法一般来说是 switch 变量或表达式,case 常量,比如:一个百分制成绩,90 及 90 分以上算优秀,80 及以上 90 以下算良好,60 及以上 80 以下算合格,60 以下为不合格,用 switch 表示这样写:
function calcGrade(score) { const line = score / 10 | 0; switch (line) { case 10: case 9: return "优秀"; case 8: return "良好"; case 7: case 6: return "合格"; default: return "不合格"; } }
代码中score / 10 | 0和Math.floor(score / 10)是一样的效果,就是除以 10 取商的整数部分。
这段 switch 用得中规中矩,用取整的办法来避免使用一长串 if ... else 分支也算是取了巧。
但现在将合格和良好的分隔点从 80 分降到 75 分,要怎么写?
其实改动不用太大,不过这次除数不再是 10,而是 5。相应地,case 也多了很多:
18、19、20 是优秀
15、16、17 是良好
12、13、14 是合格
剩下的是不合格
写 9 个 case,真不如用 if ... else 算了。
switch简单写法
是吗?其实用 switch 也有简单一些的写法:
function calcGrade(score) { switch (true) { case score >= 90: return "优秀"; case score >= 75: return "良好"; case score >= 60: return "合格"; default: return "不合格"; } }
这其实是switch 常量 case 表达式!这段跑程序没问题,是因为——switch 和 case 是按 === 来匹配的,它并不在乎是表达式还是常量,或者说,switch 和 case 后面都可以接表达式!
是的,表达式!
所以上面那个示例中,把switch(true)改成switch( 2 > 1)也是一样的效果。
好啦,脑洞已开。switch 到底有多少种写法已经不重要了。接下来要研究的是 switch 的变种 。
IIFE 封装
看到 C# 有 switch 表达式,眼馋,能实现吗?
不用眼馋,JavaScript 里一切都可以是表达式 …… 如果不是,用 IIFE 封装一个就是了
function calcGrade(score) { return (value => { switch (true) { case value >= 90: return "优秀"; case value >= 75: return "良好"; case value >= 60: return "合格"; default: return "不合格"; } })(score); }
注意这里把score作为 IIFE 的参数,是因为在实际使用中,可能需要传入的是一个表达式。这种情况下应该提前求值,而且只求一次(避免替在的副作用)。
封成策略
不过这样的封装显然没什么意义,如果真要这样封装,不如封成策略:
function calcGrade(score) { return ((value, rules) => rules.find(({ t }) => t(value)).v)( score, [ { t: n => n >= 90, v: "优秀" }, { t: n => n >= 75, v: "良好" }, { t: n => n >= 60, v: "合格" }, { t: () => true, v: "不合格" }, ] ); }
每项策略都是一个含有 tester (t) 和值 (v) 的对象。tester 是一个判断函数,传入需要判断的值,也就是switch (表达式)这里表达式,而这个表达式也是提前求值之后作为 IIFE 的参数传入的。应用策略的过程简单粗暴,就是找到第一个符合条件的策略,把它的值取出来。
当然这样用策略有点大材小用。真正需要用策略的情况,策略中通常不是一个值,而是一个行为,也就函数。
我们知道在 switch 语句中,各个 case 之间是在同一个作用域内,所以不能在两个 case 语句中声明同一个局部变量。虽然用{ }包裹可以解决这些问题,但代码看起来不怎么好看,特别是还要注意不要忘了break。如果用策略的话,看起来可能会顺眼一眼,也不用担心 break 的问题:
这里为了演示,在策略行为中将先输出成绩,再返回等级。
function calcGrade(score) { return ((value, rules) => rules.find(({ t }) => t(value)).fn(value))( score, [ { t: n => n >= 90, fn: score => { const grade = "优秀"; console.log(grade, score); return grade; } }, { t: n => n >= 75, fn: score => { const grade = "良好"; console.log(grade, score); return grade; } }, { t: n => n >= 60, fn: score => { const grade = "合格"; console.log(grade, score); return grade; } }, { t: () => true, fn: score => { const grade = "不合格"; console.log(grade, score); return grade; } }, ] ); }
代码长是融入逻辑,如果真的是要当作 switch表达式来用的话,策略部分应该是一个表达式就不会太长。上面的代码中,策略行为相似,可以封装成一个函数,这样就能写成表达式的形式了:
function calcGrade(score) { const printGrade = (grade, score) => { console.log(grade, score); return grade; }; return ((value, rules) => rules.find(({ t }) => t(value)).fn(value))( score, [ { t: n => n >= 90, fn: score => printGrade("优秀", score) }, { t: n => n >= 75, fn: score => printGrade("良好", score) }, { t: n => n >= 60, fn: score => printGrade("合格", score) }, { t: () => true, fn: score => printGrade("不合格", score) }, ] ); }
现在看起来是不是像样了?
其实很多时候书写表达只要代码合适就可以。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/127675.html
摘要:对于来说,表示元素,除了优先级更高之外,与选择器相同。再做实验,前后分别设置两个空格时,获取到的值只有一个空格。结论设置值内联样式选择器选择器也都是会把多余空格变成一个空格。 今天突然发现一个有趣的现象document.querySelector(:root) === document.documentElement showImg(https://segmentfault.com/i...
摘要:对于来说,表示元素,除了优先级更高之外,与选择器相同。再做实验,前后分别设置两个空格时,获取到的值只有一个空格。结论设置值内联样式选择器选择器也都是会把多余空格变成一个空格。 今天突然发现一个有趣的现象document.querySelector(:root) === document.documentElement showImg(https://segmentfault.com/i...
摘要:是阿里团队开发的前端适配方案,也是用的的方法。那么第一种方法其实已经能解决前端适配问题了,为什么阿里还要开发一个呢在第一种方法中,时没有任何问题,但是在或者更高的手机屏幕上,因为物理像素的增加,存在小于的显示空间。 话说我刚工作的时候,就开始用rem了,过了没多久,接触到了flexible,系统化且支持iOS的retina屏迅速征服了我,最近又看到了大漠大神的vw。所以本文想完成一篇一...
摘要:是阿里团队开发的前端适配方案,也是用的的方法。那么第一种方法其实已经能解决前端适配问题了,为什么阿里还要开发一个呢在第一种方法中,时没有任何问题,但是在或者更高的手机屏幕上,因为物理像素的增加,存在小于的显示空间。 话说我刚工作的时候,就开始用rem了,过了没多久,接触到了flexible,系统化且支持iOS的retina屏迅速征服了我,最近又看到了大漠大神的vw。所以本文想完成一篇一...
摘要:是阿里团队开发的前端适配方案,也是用的的方法。那么第一种方法其实已经能解决前端适配问题了,为什么阿里还要开发一个呢在第一种方法中,时没有任何问题,但是在或者更高的手机屏幕上,因为物理像素的增加,存在小于的显示空间。 话说我刚工作的时候,就开始用rem了,过了没多久,接触到了flexible,系统化且支持iOS的retina屏迅速征服了我,最近又看到了大漠大神的vw。所以本文想完成一篇一...
阅读 498·2023-03-27 18:33
阅读 706·2023-03-26 17:27
阅读 606·2023-03-26 17:14
阅读 575·2023-03-17 21:13
阅读 498·2023-03-17 08:28
阅读 1753·2023-02-27 22:32
阅读 1259·2023-02-27 22:27
阅读 2065·2023-01-20 08:28