表驱动法
表驱动法就是一种编程模式(scheme)——从表里面查找信息而不使用逻辑语句(if
和case)。事实上,凡是能通过逻辑语句来选择的事物,都可以通过查表来选择。对简单的情况而言,使用逻辑语句更为容易和直白。但随着逻辑链的越来越复杂,查表法也就愈发显得更具吸引力。
直接访问
一个很简单的例子: 今天星期几
const day = new Date().getDay()
let day_zh;
if(day === 0){
day_zh = '星期日'
}else if(day === 1) {
day_zh = '星期一'
}
...
else{
day_zh = '星期六'
}
// 或者 用 switch case
switch(day) {
case 0:
day_zh = '星期日'
break;
case 1:
day_zh = '星期一'
break;
...
}
实现同样功能的一种更简单、更容易修改的方法是把这些数据存到一张表里面。
const week = ['星期日', '星期一',..., '星期六']
const day = new Date().getDay(
const day_zh = week[day]
第二个例子:假设你需要一个可以返回每个月中天数的函数(为简单起见不考虑闰年)
使用if else
function iGetMonthDays(iMonth) {
let iDays;
if(1 == iMonth) {iDays = 31;}
else if(2 == iMonth) {iDays = 28;}
else if(3 == iMonth) {iDays = 31;}
else if(4 == iMonth) {iDays = 30;}
else if(5 == iMonth) {iDays = 31;}
else if(6 == iMonth) {iDays = 30;}
else if(7 == iMonth) {iDays = 31;}
else if(8 == iMonth) {iDays = 31;}
else if(9 == iMonth) {iDays = 30;}
else if(10 == iMonth) {iDays = 31;}
else if(11 == iMonth) {iDays = 30;}
else if(12 == iMonth) {iDays = 31;}
return iDays;
}
使用表驱动(包括闰年判断)
const monthDays = [
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
]
function getMonthDays(month, year) {
let isLeapYear = (year % 4 === 0) && (year % 100 !== 0 || year % 400 === 0) ? 1 : 0
return monthDays[isLeapYear][(month - 1)];
}
console.log(getMonthDays(2, 2000))
对象中的应用
形如:
if (key = "Key A")
{
处理 Key A 相关的数据。
}
else if (key = "Key B")
{
处理 Key B 相关的数据。
}
或
if (key = "Key A")
{
执行 Key A 相关的行为。
}
else if (key = "Key B")
{
执行 Key B 相关的行为。
}
可以改装成:
let table = {
A: {
data: "数据1",
action: "行为1"
},
B: {
data: "数据2",
action: "行为2"
}
}
function handleTable(key) {
return table[key]
}
console.log(handleTable('A').data)
或
let table = {
A: {
data: "数据1",
action () {
console.log('action 1')
}
},
B: {
data: "数据2",
action () {
console.log('action 2')
}
}
}
function handleTable(key) {
return table[key]
}
handleTable('A').action()
回顾一下我以前写的代码,好多复杂的代码都通过这种方式简化了不少,比如:
let vm = this
let adTable = {
bdkq () {
window.clLib.localStorageOperating.updateData('default_hospital_code', '871978')
vm.$router.push('/hospital')
},
etyy () { vm.goSp(10012) },
szn () { vm.goCh('szn') }
}
adTable[data.key] ? adTable[data.key]() : location.href = data.ad_url
以前是怎么写的呢? 看看就知道了,特别复杂!
switch (data.key) {
case 'bdkq':
window.clLib.localStorageOperating.updateData('default_hospital_code', '871978')
this.$router.push('/hospital')
break
case 'etyy':
this.goSp(10012)
break
case 'szn':
this.goCh('szn')
break
default:
location.href = data.ad_url
break
}
阶梯访问
这种方法不像索引访问那么直接,但比索引访问要节省空间。
典型的例子就是等级评定
考试按分数评优良中差四个等级
简单做法
let level = '优'
if(score <60 ){
level = '差'
}else if(score < 80) {
level = '中'
}else if(score < 90) {
level = '良'
}
如果需要添加等级 60-70 之间 是一般,就需要改逻辑,逻辑简单的还好
let level = '优'
if(score <60 ){
level = '差'
}else if(score < 70) {
level = '一般'
}else if(score < 80) {
level = '中'
}else if(score < 90) {
level = '良'
}
这时用阶梯查询就比较方便,而且扩展性也好
const levelTable = ['差', '中', '良', '优']
const scoreCeilTable = [60, 80, 90, 100]
function getLevel(score) {
const len = scoreCeilTable.length
for(let i = 0; i < len; i++) {
const scoreCeil = scoreCeilTable[i]
if(score <= scoreCeil) {
return levelTable[i]
}
}
return levelTable[len - 1]
}
就算后面需要添加等级60-70 —> ‘一般’ 也只需要简单添加数据表就可以了,而不需要修改逻辑
const levelTable = ['差', '一般', '中', '良', '优']
const scoreCeilTable = [60, 70, 80, 90, 100]
阶梯访问表需要注意几个问题
- 留心端点
- 二分查找替代顺序查找:上面例子用了顺序查找,当数据比较大时,查找成本还是比较大的,应该考虑用二分查找替代顺序查找
- 考虑用索引访问来取代阶梯技术,阶梯查找比较耗时,如果速度非常重要,可以用索引访问来取代阶梯,用空间换时间,但也要分情况,因为离散空间是不能够完全替代连续空间的
表驱动法是一种编程模式,用于替代复杂的if-else或switch-case语句。通过将数据存储在表中,实现更简洁、易维护的代码。文章介绍了直接访问、阶梯访问等应用场景,并展示了如何在处理星期几、月份天数以及评分等级等场景下运用表驱动法,提高代码的可读性和可扩展性。同时,讨论了在阶梯访问中注意的端点处理、二分查找优化等问题。
2283

被折叠的 条评论
为什么被折叠?



