今天小编给大家分享的是JS语法有C#的switch表达式,相信很多人都不太了解,为了让大家更加了解,所以给大家总结了以下内容,一起往下看吧。一定会有所收获的哦。
于 C/Java 语系的语言,都有 switch 语法。switch 语法用于多分支是一个标准的用法,但这个分支语法的各分支之间存在穿透性,所以需要 break
来切断逻辑,这也成为 switch 语法中最重要的一个替在缺陷来源。此外,由于 switch 语句中各 case 的代码是在同一个作用域中,也会对代码造成一些不便。
C# 8.0 引入了 switch 表达式。C# 的 switch 表达式有着非常丰富的语法元素,可以和模式匹配和解构等语法元素协同工作 —— 这些都不在这里细说,但是对传统的 switch 语句 进行了一些改进:
新的约束
switch 表达式一定要详尽(逻辑一定会走进某一个 case,可以通过弃元模式兜底),否则可能会在运行时引发异常。
在 C# 8.0 发布的同年,Java 12 也发布并引入了 switch 表达式预览。Java 的 switch 表达式实现比较简单,就是 switch 语句到 switch 表达式的直接转换,仅支持等值匹配。直到 2023 年 3 月 Java 20 发布,switch 表达式才开始支持模式匹配。相比之下,Kotlin 的 when 表达式走在了前面。
在这个问题上 JavaScript 似乎走在了后面,不过在语言提供 switch 表达式之前,我们可以尝试自己造个轮子。
思路当然是参考策略模式。假设有一个列表,这个列表里的每个元素都包含了两个因素:第一个用于判断是否命中,第二个是个函数,得到一个计算结果。然后写一个循环遍历列表的每个元素,一旦某个元素命中,就执行元素携带的函数获得结果,中断循环,返回结果。如果列表的最后一个元素必定命中,那么这个列表就是“详尽”的。
when 函数写法
那么这个 when
函数可能会这样写(switch
是关键字,所以使用 when
来作为函数名):
// JS function when(value, ...cases) { for (const { is, run } of cases) { if (is(value)) { return run(value); } } throw new Error("非详尽"); }
这里我们假设每个情况 (case) 都含有 is
方法用于判断是否命中,用 run
方法保存命中后需要执行的操作。
分算等级”测试
相应地,我们可以经典的“拿分算等级”来进行测试:
// JS function calcGrade(score) { return when( score, { is: v => v >= 0 && v < 80, run: v => `不合格 (${v})` }, { is: v => v >= 80 && v < 100, run: v => `合格 (${v})` }, { is: v => v == 100, run: v => `满分 (${v})` }, { is: _ => true, run: v => `无效 (${v})` }, ); } for (let i = 0; i < 50; i++) { const v = 70 + ~~(Math.random() * 35); console.log(calcGrade(v)); }
在 calcGrade
实现中 when
的 case 列表最后一项采用了“永真”断言,所以走到这一项的时候一定会命中,从逻辑上来永远不会触发 Error。如果是非“详尽”的情况列表,就有可能触发 Error。
测试问题
不过现在从测试代码中就发现了两个问题:
继续改进 ——
// JS function when(value) { // when 的参数先给 switch 的值 // 返回一个函数来处理分支匹配 ② return function (...cases) { for (const [is, run] of cases) { // ^^^^^^^^^ 从对象改为元组(数组)③ if (value === is || (typeof is == "function" && is(value))) { // ^^^^^^ 精确判断 ① // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 断言函数判断 return run(value); // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 可指定行为(函数) } } throw new Error("非详尽"); }; } function calcGrade(score) { return when(score)( // ^^^^^^^^^^^ 这里返回的是匹配处理的函数 [v => v >= 0 && v < 80, v => `不合格 (${v})`], [v => v >= 80 && v < 100, v => `合格 (${v})`], [100, () => "满分 (100)"], // ^^^ 可以指定匹配的值 // ^^ 计算不需要参数,可以不声明 [_ => true, v => `无效 (${v})`], // ^^^^^^^^^ 兜底的永真断言 ); }
为什么兜底断言必须使用一个函数呢?因为 true
值也有可能是对应一种预想的分支情况。由于这个 when
是通过语义来实现而不是通过语法来实现的,所以这里没办法定义一个安全的兜底断言语法,只有用断言函数会相对安全。
升级成 TypeScript
至此为止我们已经基本实现了 switch 表达式 (when),把它升级成 TypeScript
// TypeScript type CaseCondition<T> = T extends Function ? never : ((t: T) => boolean) | T type Case<T, R> = [CaseCondition<T>, (t: T) => R]; function when<T>(value: T): <R>(...cases: Case<T, R>[]) => R { return function<R>(...cases: Case<T, R>[]): R { for (const [is, run] of cases) { if (value === is || (typeof is == "function" && is(value))) { return run(value); } } throw new Error("非详尽"); }; } function calcGrade(score: number) { return when(score)( [v => v >= 0 && v < 80, v => `不合格 (${v})`], [v => v >= 80 && v < 100, v => `合格 (${v})`], [100, () => "满分 (100)"], [_ => true, v => `无效 (${v})`], ); }
这段代码当然可以直接用,但是如果使用 npm 可能会更方便一点:
npm install @jamesfancy/when
// TypeScript import { when } from "@jamesfancy/when"; function calcGrade(score: number) { return when(score)( [v => v >= 0 && v < 80, v => `不合格 (${v})`], [v => v >= 80 && v < 100, v => `合格 (${v})`], [100, () => "满分 (100)"], [_ => true, v => `无效 (${v})`], ); }
关于JS语法有C#的switch表达式就分享到这里了,希望以上内容可以对大家有一定的参考价值,可以学以致用。如果喜欢本篇文章,不妨把它分享出去让更多的人看到。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。