Conditional branching is when a segment of code is executed or evaluated based on a condition, typically implemented using an if...else construct.

条件 分支是根据条件执行或评估一段代码时的条件 分支 ,通常使用if...else构造实现。

For example:


if (customerPaid)

Here, sendThankYou() will get called if customerPaid is true; otherwise sendReminder() will be called.

在这里,如果customerPaidtrue ,则将调用sendThankYou() ; 否则将调用sendReminder()

There’s some thinking in the programming community that if should be considered harmful or a code smell. Regardless of the validity of this claim, there may be cases where if isn’t the best approach to branching, or where branching should be avoided altogether.

一些想法在编程社区if应被认为是有害的或代码味道。 无论此声明的有效性如何,在某些情况下, if不是最好的分支方法,或者应完全避免分支。

In this tutorial, I’ll therefore demonstrate six alternatives to if...else with some discussion on when you might choose to use them.


Examples are written in JavaScript, but the concepts are applicable in many other languages.


1.三元运算符 (1. The Ternary Operator)

One of my favourite alternatives to if...else is the ternary operator.


This takes the form:


condition ? expressionIfTrue : expressionIfFalse

Here expressionIfTrue will be evaluated if condition evaluates totrue; otherwise expressionIfFalse will be evaluated.

如果condition值为true ,则将对expressionIfTrue进行评估; 否则将评估expressionIfFalse

The beauty of ternary operators is they can be used on the right-hand side of an assignment.


For example:


const labelText = customerPaid ? "Thank You!" : "Payment Overdue";

This will set labelText to “Thank You!” if the customer has paid; otherwise, you’ll get “Payment Overdue”.

这会将labelText设置为“Thank You!” 客户是否已付款; 否则,您将收到“Payment Overdue”

2. Switch语句 (2. The Switch Statement)

A switch statement has the following structure:


switch (expression)
  case value1:
    // code executed if expression matches value1
  case value2:
    // code executed if expression matches value2
  case valueN:
    // code executed if expression matches valueN
     // code executed if expression has no match

The break statements are optional and will cause the switch block to be exited. If a break is omitted, then execution will proceed to the next case statement.

break语句是可选的,将导致退出switch块。 如果省略break ,则执行将继续执行下一个case语句。

switch is useful for branching based on a homogeneous set of values.


For example:


switch (colour)
    case 'red':
    case 'amber':
    case 'green':
    case 'flashing amber':
         throw 'Invalid colour';

3.跳转表 (3. The Jump Table)

A jump table is a method of conditionally branching using a lookup table to branch into a new function or block.


Technically in C, this would be implemented as an array of function pointers. However, unless we strictly need the efficiency of array lookup, we could generalise this to any kind of keyed function lookup.

从技术上讲,这将以C 函数指针数组的形式实现。 但是,除非我们严格需要数组查找的效率,否则我们可以将其推广到任何类型的键控函数查找。

For example, the above switch statement could be refactored as a jump table in JavaScript, like so:


const handleColour = 
'red' : stop,
'amber' : stop,
'green' : go,
'flashing amber' : go

Here stop and go are function objects. Let’s flesh this out a bit to make it clear how this approach would work in context:

stopgo是功能对象。 让我们充实一下,以明确此方法在上下文中的工作方式:

const stop = () => { console.log("stop called"); }
const go = () => { console.log("go called"); }

const colour = 'red';

const handleColour = 
    'red'               : stop,
    'amber'             : stop,
    'green'             : go,
    'flashing amber'    : go

handleColour[colour]();   // logs "stop called"

Here, our code branches conditionally based on the value of the colour variable. The semantics are the same as our switch example, but we have less code. And it’s (arguably) clearer to read.

在这里,我们的代码根据colour变量的值有条件地分支。 语义与我们的switch示例相同,但是代码更少。 而且(可以说)阅读起来更清晰。

4.动态调度 (4. The Dynamic Dispatch)

Another alternative to using if statements is a dynamic dispatch. This involves selecting which polymorphic method to call based on an object’s type.

使用if语句的另一种选择是动态分配。 这涉及根据对象的类型选择要调用的多态方法。

It could be used to branch conditionally, like this:


const handleShape = (shape) => { console.log(shape.area()); }

class Shape
    constructor(width = 2)
        this.width = width;
         return 0;

class Square extends Shape
        return this.width ** 2;  

class Circle extends Shape
        return Math.PI * (this.width / 2) ** 2;

const shape = new Square();

handleShape(shape);    // logs 4

Here, a different code path is taken depending on the type of object passed to the handleShape function. In our case, Shape is a Square, so the area is logged as 4.

在此,根据传递给handleShape函数的对象类型,采用不同的代码路径。 在我们的例子中, Shape是一个Square ,因此该区域记录为4

This approach can result in a lot more code, but there are some arguments for its usage over an if...else. This kind of pattern is generally appropriate when the code already employs OOP; however, seeking to always engineer branching to use polymorphism seems like overkill.

这种方法可以产生更多的代码,但是在if...else一些使用它的参数 。 当代码已经采用OOP时,这种模式通常是合适的; 但是,试图始终设计分支以使用多态性似乎有些过头。

try' and 'catch' statements (5. ‘try' and 'catch' statements)

I’m including this for completeness since try/catch should rarely, if ever, be used for control flow.

我将其包括在内是为了完整性,因为try / catch应该很少(如果有的话)用于控制流程。

Much has been written about why this is a bad idea, but my personal take is that try/catch are designed for handling exceptions, so by using them for control flow, our intent becomes unclear.

关于为什么这样做不是一个好主意的文章已经写很多 ,但是我个人认为try / catch是为处理异常而设计的,因此通过将它们用于控制流,我们的意图变得不清楚。

In any case, here’s an example of conditional branching using exceptions:


var item;

    item = previousItem;
catch (ReferenceError)
    item = new Item();
    previousItem = item;

Here, item will get assigned topreviousItem if it exists; otherwise, a ReferenceError exception will be thrown, and a new Item object will be assigned.

在这里, item将被分配给previousItem如果存在); 否则,将抛出ReferenceError异常,并分配一个新的Item对象。

6.模式匹配 (6. Pattern Matching)

Pattern matching is the new kid on the block when it comes to branching. It’s generally popular with those who favour a more functional programming style.

模式匹配是分支方面的新手。 它在那些偏爱功能更强大的编程风格的人中普遍流行。

Pattern matching could be thought of as dynamic dispatch (see above) based on a value rather than a type.


A classic example is implementing a factorial function using two functions:


factorial(0) ::= 1
factorial(n) ::= n * factorial(n-1)

The first is called if the value passed in is zero, in which case 1 is returned. The second is called if the value passed in is nonzero — in which case, the result of the expression n * factorial(n-1) is returned.

如果传入的值为零,则调用第一个,在这种情况下,将返回1 。 如果传入的值非零,则调用第二个方法-在这种情况下,将返回表达式n * factorial(n-1)的结果。

Some languages have pattern matching built in. In JavaScript, an external library needs to be used — for example, Z (pattern matching for Javascript).

某些语言内置了模式匹配。在JavaScript中,需要使用一个外部库,例如Z(Java的模式匹配 )。

The factorial function could be written using Z as follows:


var factorial = number => {
return number.matches (
(x = 0) => 1,
(x) => x * factorial (x - 1)
factorial(6) // returns 720

There are arguably more readable and expressive ways to compute a factorial in JavaScript, but the potential for pattern matching as a means of conditional execution extends well beyond this simple example.


There is a proposal to build a pattern into the JavaScript language, which is worth a read.


结论 (Conclusion)

Conditional branching can introduce complexity into a program.


Nested if and switch statements can make code less readable and open potential for bugs. Other forms of branching can result in an overengineered codebase. If it’s possible to avoid branching altogether, this is often a good starting point.

嵌套的ifswitch语句可能会使代码的可读性降低,并可能引发错误。 其他形式的分支会导致代码库过度设计。 如果有可能完全避免分支,这通常是一个很好的起点。

However, if we do need to conditionally branch, it’s good to choose the most appropriate mechanism for the job. Hopefully, in the article I’ve provided some useful options for consideration.

但是,如果确实需要有条件地分支,则最好选择最合适的工作机制。 希望本文中提供了一些有用的选项供您考虑。

翻译自: https://medium.com/better-programming/5-alternatives-to-if-statements-for-conditional-branching-6e8e6e97430b

  • 1
  • 0
  • 3
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
钱包余额 0