What is control flow?

Control flow refers to the order in which expressions and statements (and entire blocks of code) will run. Programming is, in part, the art of controlling flow. By writing code, we are specifying where control resides at any single moment. 

At a granular level, the order of execution is dictated by the individual operators we use in our expressions. We explored the precedence and associativity of operators in the last chapter, discovering that, even if you have a series of operators, one after another, the exact order of their execution is defined by the individual operators' precedence and associativities so that, in the expression, 1 + 2 * 3, the 2 * 3 operation will occur before the addition.

Outside expressions, on the statement level, we control flow in the following ways:

  • We can do so by ordering our statements in the order we wish them to occur.
  • We can do so by using conditional or iterative language constructs, including the following:
    • switch() statements
    • if() statements
    • for() statements
    • while() statements
    • do{...} while() statements
  • We can do so by invoking and then returning or yielding from functions or generators (yielding and returning are both ways of giving back control to the caller).

It's easiest to imagine the control flow globally as a type of cursor or finger that is always pointing to a specific expression or statement of code. When a program is executing, the control flow will go down, line by line, until it encounters a piece of syntax that will redirect control to another piece of code. If it encounters an invocation of a function, then that function will be executed in the same manner; the control will be with each consecutive line within the function until it is returned to the caller of the function via a return statement. As control traverses down through a program, each language construct it encounters will be given control over the execution until they each complete. Consider the following simple piece of code:

let basket = [];
for (let i = 0; i < 3; i++) {
basket.push(
makeEgg()
);
}

The flow of control that is taken in the preceding code is as follows:

  1. We start with let basket = [];
  2. The for loop begins: let i = 0
  3. Check i < 3 (true!):
    1. Run makeEgg()
    2. Push result via basket.push(...)
    3. i++ (i is now 1)

  1. Check i < 3 (true!):
    1. Run makeEgg()
    2. Push the result via basket.push(...)
    3. i++ (i is now 2)
  2. Check i < 3 (true!):
    1. Run makeEgg()
    2. Push result via basket.push(...)
    3. i++ (i is now 3)
  3. Check i < 3 (false!).
  4. End of Program

Even for quite a simple program such as this, the flow can be quite complicated and lengthy. For the benefit of our fellow programmers, it makes sense to try to reduce this complexity whenever possible. The way to accomplish this is via abstraction. Abstracting something won't eliminate that complexity, but it will hide it so that programmers don't need to concern themselves with it. Therefore, before delving into the specific language constructs of control flow in JavaScript, we'll be exploring how these concepts of control flow and abstraction interrelate via the two opposing approaches of imperative and declarative programming.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.252.204