多个if else条件的替代方法

11

我有多个要检查和执行的条件,就像下面这样。

if (date == current_date && source === "s3") {
    table_name = "Table1";
} else if (date == current_date && source !== "s3") {
    table_name = "Table2";
} else if (date !== current_date && source === "s3") {
    table_name = "Table3";
} else if (date !== current_date && source !== "s3") {
    table_name = "Table4";
}

我认为在这里使用 switch 语句没有意义,因为我们没有将 case 语句表达式与 switch 表达式进行比较。

那么,使用多个 if else 语句或者其他更好的替代方法是否可行?


如何使用 hash = {"Table1current":"Table1", "Table1notcurrent":"Table4", etc....}',然后只需 table_name = hash[table + current]?这样,你的条件被表示为 JSON 结构,更易读、解析等。 - HoldOffHunger
1
if (date=== current_date) { table_name = source === "s3" ? "Table1" : "Table2" } else { table_name = source === "s3" ? "Table3" : "Table4" } - epascarello
1
在这个特定的情况下:index = 4 - (2 * +(date === current_date) + +(source === 's3')); table_name = 'Table' + index; - Teemu
1
@Teemu 哈哈,太棒了!而且它还展示了在提问时匿名化代码的问题:人们会发现仅适用于您使用的占位符的惊人技巧 :) - sp00m
你对于多个if else语句有什么顾虑,为什么认为这些不是switch语句可以处理的情况(实际上它们是),当你说“更好的替代方法”时,如何量化“更好”? - TylerH
@sp00m …尽管Q已经被关闭了,我对“最过度工程解决方案”比赛感到挑战。这种方法基于JavaScript的Boolean.prototype的Smalltalk启发式ifTrue / ifFalse实现。OP的示例代码被转换为“概念证明”的测试。 - Peter Seliger
8个回答

8

你的代码是100%好的选择。只是有点难以阅读。你可以将常用代码提取到变量中,使其更易读。

var isCurrent = date == current_date;
var isS3 = source === "s3";

if (isCurrent && isS3) {
    table_name = "Table1";
} else if (isCurrent && !isS3) {
    table_name = "Table2";
} else if (!isCurrent && isS3) {
    table_name = "Table3";
} else {
    table_name = "Table4";
}

另一种选择是使用三元运算符。

var isCurrent = date == current_date;
var isS3 = source === "s3";

if (isCurrent) {
    table_name = isS3 ? "Table1" : "Table2";
} else {
    table_name = isS3 ? "Table3" : "Table4";
}

它可能可以是一个大三目运算符,但它有点难以阅读。

var isCurrent = date == current_date;
var isS3 = source === "s3";

table_name = isCurrent ? 
    (isS3 ? "Table1" : "Table2") :
    (isS3 ? "Table3" : "Table4");

5
在这种情况下,如果我们将其简化为嵌套的if语句,可能会更容易理解:
if (date == current_date) {
  if (source === "s3") {
    table_name = "Table1";
  } else {
    table_name = "Table2";
  }
} else {
  if (source === "s3") {
    table_name = "Table3";
  } else {
    table_name = "Table4";
  }
}

这种方法最多只进行了 2 次逻辑比较,而通过使用程序控制,可以达到相同的逻辑结果。而你的方法可能需要...... 最多 8 次?

但是现在,这主要是一个吹毛求疵的样式问题,而且评论中有一些很好的想法。例如,如果您希望此逻辑增长,那么使用 Map/Object 存储此信息会更有意义。

是的, switch 语句并没有太多意义。


3

这是我参加“最过度工程化解决方案”比赛的申请:

const bools = [
  date === current_date,
  source === "s3",
  // more?
];

const mask = bools.reduce((x, e) => x + +e, "");
// [ false, false ] --> 00
// [ true,  false ] --> 10
// [ false, true  ] --> 01
// [ true,  true  ] --> 11

switch (mask) {

  case "00":
    table_name = "Table4";
    break;

  case "01":
    table_name = "Table3";
    break;

  case "10":
    table_name = "Table2";
    break;

  case "11":
    table_name = "Table1";
    break;

  default:
    // noop
    break;

}

如果您愿意,这里可以再加一个面罩来进行切换,这次是数字形式:

const mask = bools.reduce((x, e, i) => x + e * Math.pow(2, i), 0);
// [ false, false ] --> 0
// [ true,  false ] --> 1
// [ false, true  ] --> 2
// [ true,  true  ] --> 3

否则,只需使用你的老朋友 - if。 :)

2

如果您想要更清晰的抽象,可以尝试使用模式匹配库,例如tailored

const { wildcard, clause, defmatch } = require('tailored')

const _ = wildcard()

const nonCurrentDate = new Date(0).toISOString()
const currentDate = new Date().toISOString()

const tableName = defmatch(
    clause([ currentDate, 's3' ], () => 'Table1'),
    clause([ currentDate, _    ], () => 'Table2'),
    clause([ _          , 's3' ], () => 'Table3'),
    clause([ _          , _    ], () => 'Table4'),
)

console.log(
    tableName(currentDate, 's3'), // Table1
    tableName(currentDate, '!!'), // Table2
    tableName(nonCurrentDate, 's3'), // Table3
    tableName(nonCurrentDate, '!!'), // Table4
)

Try on RunKit


2
如何将条件存储在JSON结构中?像这样...
hash = {"Table1current":"Table1", "Table1notcurrent":"Table4", etc....};

然后要访问您想要的值,只需执行...
table = "Table1";
current = date == current_date ? 'current' : 'notcurrent';
table_name = hash[table + current];

这样,您的条件就被表示为一个JSON结构,它有更多的优点:

  • 可读性强,即使没有编程技能的人也能理解。
  • 计算机解析器可以读取、验证和确认。
  • JSON文件可以存储在代码之外,并且只在需要时由JS加载。
  • 通过将数据与代码分离,人们可以在不影响代码的情况下处理数据,反之亦然。

1
您可以使用位掩码来生成表格,如下所示:

let getTable = (date, source) => {
    let currentMask = (date === current_date) ? 0 : 2; // turns on twos bit if not current date.
    let s3Mask = (source === "s3") ? 0 : 1; // turns on ones bit if not s3.
    let idx = (currentMask | s3Mask) + 1;
    return 'Table' + idx;
}

let current_date = 1; // hard code current date for testing.

console.log(getTable(1, "s3"));
console.log(getTable(1, "something"));
console.log(getTable(2, "s3"));
console.log(getTable(2, "something"));


1
如果简洁是您的目标,这就是最小的尺寸。
var table_name = (date == current_date && source === 's3') ? 'Table1' : (date == current_date && source !== 's3') ? 'Table2' : (date != current_date && source === 's3') ? 'Table3' : 'Table4';

0
通常情况下,使用多个if else语句是可以的。通常情况下,正确答案取决于上下文(条件数量、代码内部等)。
我不同意switch语句严格来说没有意义。switch语句可能有意义(当然,这取决于上下文),可以使用switch(true)结构:
switch (true) {
    case date == current_date && source === "s3":
        table_name = "Table1";
        break;
    case date == current_date && source !== "s3":
        table_name = "Table2";
        break;
    case date !== current_date && source === "s3":
        table_name = "Table3";
        break;
    case date !== current_date && source !== "s3":
        table_name = "Table4";
        break;
}

在JavaScript中,case不仅可以是静态值,还可以是表达式。
如果选择这种方法,请注意结果与true进行严格比较,因此并非所有“真值”都适用。
在某些情况下,这种方式可能更易读。

1
使用比较语句的 switch 通常被认为是不良实践。有趣的是,它实际上会使代码变得更长,哈哈。 - epascarello
@epascarello你有没有关于不良实践声明的参考资料?关于较长的代码,你是指 break 吗?用 return 可以让它更短... 无论如何,较长的代码并不等于更糟糕的代码,往往恰恰相反。正如我所说(也许应该更强调一下),这取决于上下文。 - Jan Stránský

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接