本文扩展了 Todd Motto 关于用对象字面量替换 switch 语句的想法。这是过时、笨拙且冗长的 switch
语句的一种非常简洁美观的替代方法。在本文的最后,您将获得一个基于 Todd 解决方案的实用程序函数,该函数对开发人员更加友好,因此请坚持到最后!
如果您对技术细节不感兴趣,只想了解实用程序函数,请向下滚动到最后一节(您需要的一切都在一个地方)。
虽然 switch 语句在某些情况下很有用,但许多人认为它不是 Javscript 最适合其用途的设计。它不如其他结构灵活、可读和可维护。
例如,对 switch
语句的主要批评之一是其贯穿行为。如果您忘记在 case
的末尾包含 break
语句,则控制权将贯穿到下一个 case
,从而导致意外行为,如下面的示例所示。这可能会使代码更容易出错且更难维护。
switch (fruit) {
case 'apple':
console.log('Apple selected');
// Missing break statement, falls through to the next case
case 'orange':
console.log('Orange selected');
break;
case 'banana':
console.log('Banana selected');
break;
default:
console.log('Unknown fruit');
}
在这个示例中,如果 fruit 为 'apple'
,则 "Apple selected"
和 "Orange selected"
都将被记录。
与 switch
语句相比,Object Literal 更灵活、更具表现力。
以下是如何使用它们仅返回 string
值。
const getDate (unit) {
var date = {
'year': '2024',
'month': 'January',
'day': '21',
'default': 'Default value'
};
return (date[unit] || date['default']);
}
var month = getDate('month');
console.log(month); // January
有时我们需要编写更复杂的代码,而仅返回 string
是不够的。我们可以进一步改进上述代码,在其中使用函数而不是字符串,以便我们可以包含更复杂的代码。
const getDate (unit) {
var date = {
'year': () => {
// do more complicated stuff here
// just returning a string in this case
return '2024';
},
'month': () => {
return 'January';
},
'day': () => {
return '21';
},
'default': () => {
return 'Default value'
}
};
// we return the Object literal's function invoked
return (date[unit] || date['default'])();
}
var month = getDate('month');
console.log(month); // January
但是如果我们想要一个贯穿行为呢?我们可以轻松地使用对象字面量来实现这一点,它更具可读性、声明性和更不易出错。它还不会涉及添加或删除 break
,而这是我们正在寻找的。
const getDayType (day) {
const isWeekDay = () => {
return 'Weekday';
}
const isWeekEnd = () => {
return 'Weekend';
}
var days = {
'monday': isWeekDay,
'tuesday': isWeekDay,
'wednesday': isWeekDay,
'thursay': isWeekDay,
'friday': isWeekDay,
'saturday': isWeekEnd,
'sunday': isWeekEnd,
'default': () => {
return 'Default value'
}
};
// we return the Object literal's function invoked
return (days[day] || days['default'])();
}
var dayType = getDayType('sunday');
console.log(dayType); // WeekEnd
既然我们已经学会了如何使用 Object Literal 而不是 switch
,那么让我们根据学到的知识构建一个实用函数,以进一步简化我们的生活。
我们称我们的函数为 switchCase
。它接收一个具有 2 个属性的对象: cases
和 defaultCase
。Cases 是将容纳我们案例的对象字面量,而 defaultCase
是…嗯,默认案例。
const switchCase = ({cases, defaultCase}) {
}
switchCase
是一个返回回调函数的高阶函数。回调函数接收 switch 表达式。
const switchCase = ({cases, defaultCase}) {
return (expression) => {
}
}
现在,回调函数需要做的就是返回调用的对象字面量函数。
const switchCase = ({cases, defaultCase}) {
return (expression) => {
return (cases[expression] || defaultCase)();
}
}
就是这样!现在让我们看一个如何使用它的示例。
let date = new Date()
const today = switchCase({
cases: {
year: () => date.getFullYear(),
month: () => date.getMonth() + 1,
day: () => date.getDate()
},
defaultCase: () => date
})
today('year') // current year
today('month') // current month
today('day') // current day
today('century') // default case - returns the current date Object
对于 typescript 用户,我们可以利用泛型来允许以后要调用该函数的用户指定他们希望对象字面量函数返回的类型。
type SwitchCase<T> = {
cases: {[key: string]: () => T},
defaultCase: () => T
}
const switchCase = <T,>({cases, defaultCase}: SwitchCase<T>) => {
return (expression: string) => {
return (cases[expression] || defaultCase)()
}
}
这就是我们如何使用它的方式。请注意,我们不必总是指定类型,因为 Typescript 会自动推断它,除非它是多个类型的联合,如下所示。
let date = new Date()
const today = switchCase<number | Date>({
cases: {
year: () => date.getFullYear(),
month: () => date.getMonth() + 1,
day: () => date.getDate()
},
defaultCase: () => date
})
today('year') // current year
today('month') // current month
today('day') // current day
today('century') // default case - returns the current date Object
实用程序函数:
const switchCase = ({cases, defaultCase}) => (expression) => (cases[expression] || defaultCase)()
用法: Tyepscript 版本
let date = new Date()
const today = switchCase({
cases: {
year: () => date.getFullYear(),
month: () => date.getMonth() + 1,
day: () => date.getDate()
},
defaultCase: () => date
})
today('year') // current year
today('month') // current month
today('day') // current day
today('century') // default case - returns the current date Object
实用功能:
const switchCase = <T,>({cases, defaultCase}: {cases: {[key: string]: () => T}, defaultCase: () => T}) => (expression: string) => (cases[expression] || defaultCase)()
用法:
let date = new Date()
const today = switchCase<number | Date>({
cases: {
year: () => date.getFullYear(),
month: () => date.getMonth() + 1,
day: () => date.getDate()
},
defaultCase: () => date
})
today('year') // current year
today('month') // current month
today('day') // current day
today('century') // default case - returns the current date Object
点击👉这里~~