0

Now that I have a recursive function, I wonder what is best in order for the same flow to continue.

Nest an another function, isn't it?

In other words, I would like another prompt that asks the user's age when the user answers yes to the first prompt.

The issue that I'm facing now is that the last prompt does not comeback if the user writes something different than "yes" or "no".

They way I've nested it makes the prompts pop up in a way that I can't figure out:

  function showPrompt(msg) {
  var str = prompt(msg).toLowerCase();
  if (str === "yes") {

            function showPrompt(firstQuestion) {
                    var age = prompt(firstQuestion).toLowerCase();
                    if (age < 21) {
                        alert("You're too young. Go home.");
                    } else if (age >= 21) {
                        alert("Welcome.");
                    } else {
                        showPrompt(firstQuestion);
                    }       
            }

        showPrompt("How old are you?");

  } else if (str === "no") {
    alert("goodbye.");
  } else {
    showPrompt(msg);
  }
}

showPrompt("Do you like gambling?");
  • Compare numbers, comparing strings gives you unexpected results. – Teemu May 05 '20 at 12:54
  • Thank you. The issue that I have now is that the last prompt does not come back when the user answers something different than "yes" or "no". – Yann Heide Biedziński May 05 '20 at 13:02
  • 1
    run this in your console `console.log("5" > "11", 5 > 11)` and you will see why comparing strings is not the same as comparing numbers. – epascarello May 05 '20 at 13:08
  • Thank @epascarello. How would you put that last `showPrompt("Do you like gambling?");` back into the flow?` – Yann Heide Biedziński May 05 '20 at 13:13
  • You should not define functions in blocks, move it to the top level of the containing function. Then you've also to call the function (giving different names to the functions might helpt to follow what is happening). – Teemu May 05 '20 at 13:14

2 Answers2

2

The problem is that you are overwriting your function. If you give your second function another name I guess it works the way you want. And as given in the other answer, you do not need to define your function in the condotional clause:

function showPrompt(msg) {
    var str = prompt(msg).toLowerCase();
    if (str === "yes") {
        nextQuestion("How old are you?");
    } else if (str === "no") {
        alert("goodbye.");
    } else {
        showPrompt(msg);
    }
}

function nextQuestion(secondQuestion) {
    var age = parseInt(prompt(secondQuestion));
    if (typeof age == "number" && age < 21) {
        alert("You're too young. Go home.");
    } else if (typeof age == "number" && age >= 21) {
        alert("Welcome.");
    } else {
        showPrompt(secondQuestion);
    }       
}

showPrompt("Do you like gambling?");
Cimoe
  • 580
  • 6
  • 21
0

Your problem is the conditional creation of showPrompt within the function called showPrompt, see Function declarations inside if/else statements?. While such declarations are allowed, they have side effects and should be avoided.

One side effect is that the conditional function declaration creates a local variable that is undefined unless execution enters the if block and assigns it a value. In the OP, the local showPrompt declaration shadows the global showPrompt created by the global function declaration. Hence if the block is not entered, when it's called, its value is undefined and a TypeError is thrown, e.g.

// Global foo
var foo = 23;

function bar() {
  // Declaration creates a local foo even if 
  // if block is not entered
  if (false) {
    function foo (){}
  }
  // foo is undefined
  console.log(typeof foo);
}

bar();

To fix that, change the name of the function in the if block and move it out of the block.

Also, as pointed out by epascarello, you should do numeric comparisons using numbers, not strings. When using comparison operators, if one of the values is a number, then the other will be converted to number too for the comparison. But if they are both strings (prompt returns a string), they'll be compared as strings. But for readability, it's best to use numbers for both sides.

Finally, you should test the value returned by the prompt to see it's a string. If the user clicks "Cancel", it will return null and calling toLowerCase will throw an error. So if the value isn't a string, the user clicked cancel and the function should handle it (e.g. exit).

function showPrompt(msg) {

  function showPrompt2(firstQuestion) {
    var age = prompt(firstQuestion);
    
    if (typeof age != 'string') {
      return;
    }
    
    if (+age < 21) {
      alert("You're too young. Go home.");

    } else if (+age >= 21) {
      alert("Welcome.");

    } else {
      showPrompt2(firstQuestion);
    }
  }

  var str = prompt(msg);
  
  if (typeof str != 'string') {
    return;
  }
  
  str = str.toLowerCase();

  if (str === "yes") {
    showPrompt2("How old are you?");

  } else if (str === "no") {
    alert("goodbye.");
    
  } else {
    showPrompt(msg);
  }
}

showPrompt("Do you like gambling?")
RobG
  • 142,382
  • 31
  • 172
  • 209