-1

When I run this code from Notepad++ through an .html file, the output doesn't recognize my return values. It always outputs "undefined"

I've tried putting the return statement outside of the switch statement but it didn't solve anything.

Edit: I included the code that calls the function and I fixed my if statements based on iCode's tips.

// this came with the execrise
var sentinel = true

while (sentinel) {

    var month = prompt("Enter an integer from 1 to 12 inclusive, representing a month of the year");
    var request = prompt("Enter 1 if you want the name of the month, or enter 2 if you want the number of days in the month");

    if (months(month,request) == false) {
        // reset
        alert("Try again but enter the right stuff this time");

    } else {
        // output
        sentinel = false;

        if (request == 1) {

            console.log("Month number " + month + " is " + months(month,request));

        } else if (request == 2) {

            console.log("There are " + months(month,request) + " days in month number " + month);
        }
    }
}

// this is my edited code
function months(month,request) {
    if (!request || request < 1 || request > 2 || isNaN(request)) {
        return false;
    }
    if (!month || month < 1 || month > 12 || isNaN(month)) {
        return false;
    }

    var name;
    var numberDays;
    switch(month){
        case 1:
            if(request == 1){
                name = "January";
                return name;
            }else{
                numberDays = "31";
                return numberDays;
            }
            break;

        case 2:
            if(request == 1){
                name = "February";
                return name;
            }else{
                numberDays = "28";
                return numberDays;
            }
            break;

        case 3:
            if(request == 1){
                name = "March";
                return name;
            }else{
                numberDays = "31";
                return numberDays;
            }
            break;

        case 4:
            if(request == 1){
                name = "April";
                return name;
            }else{
                numberDays = "30";
                return numberDays;
            }
            break;

        case 5:
            if(request == 1){
                name = "May";
                return name;
            }else{
                numberDays = "31";
                return numberDays;
            }
            break;

        case 6:
            if(request == 1){
                name = "June";
                return name;
            }else{
                numberDays = "30";
                return numberDays;
            }
            break;

        case 7:
            if(request == 1){
                name = "July";
                return name;
            }else{
                numberDays = "31";
                return numberDays;
            }
            break;

        case 8:
            if(request == 1){
                name = "August";
                return name;
            }else{
                numberDays = "31";
                return numberDays;
            }
            break;

        case 9:
            if(request == 1){
                name = "September";
                return name;
            }else{
                numberDays = "30";
                return numberDays;
            }
            break;

        case 10:
            if(request == 1){
                name = "October";
                return name;
            }else{
                numberDays = "31";
                return numberDays;
            }
            break;

        case 11:
            if(request == 1){
                name = "November";
                return name;
            }else{
                numberDays = "30";
                return numberDays;
            }
            break;

        case 12:
            if(request == 1){
                name = "December";
                return name;
            }else{
                numberDays = "31";
                return numberDays;
            }
    }
}

                return false;
                    }
                }else{
                    return false;
                }
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

I expect the output to be either "Month number 1 is January" or "There are 31 days in month number 1"

  • 1
    https://jsbin.com/zekazezuze/1/edit?js,console - works for me – Quentin Jan 07 '19 at 19:30
  • 3
    It's not clear what you mean by running it in an HTML file. This is a Javascript function, which seems to work properly. How exactly are you trying to run it? – Scott Sauyet Jan 07 '19 at 19:30
  • What is the input? – Teemu Jan 07 '19 at 19:30
  • As Scott said, what do you mean "run it through an HTML file"? Can you post the HTML that's supposed to be executing this function? – Mike G Jan 07 '19 at 19:31
  • That code could be simplified with an object or array. If statements are overkilll.... `if (month > = 1 && month<=12) { ... }` – epascarello Jan 07 '19 at 19:32
  • Just consider that you can merge 4 if in one if if (first && second && third && forth) .. else { return false ; } ... – cvekaso Jan 07 '19 at 19:33
  • 3
    May I just point out this code looks terrible. If you nest if statements into each other and have for every if statement the same else you might as well concatenate the statements together with `&&`. This reduces nesting. An even better option is using a [guard](https://medium.freecodecamp.org/en-garde-how-you-can-refactor-nested-ifs-with-guard-clauses-in-javascript-883665517b4b), this eliminates the need to indent the main content completely. – 3limin4t0r Jan 07 '19 at 19:36
  • And code does not account for leap year.... – epascarello Jan 07 '19 at 19:38
  • 5
    Folks, this is a brand-new user here. We all can tell by the code and the question that this user is probably new to JS. Yes, this code could use some real work, but let's keep our eyes on the ball here: why doesn't it run? Of course we need some answers from the OP in order to help with that. – Scott Sauyet Jan 07 '19 at 19:42
  • I think your inparameter "month" isn't any of those numbers in the switch case. most probably the prompt call does not retrieve the user input correctly. – Laughing Lemonade Jan 09 '19 at 12:23

3 Answers3

0

A simplification of your code. The year is required to accuretly get the number of days for February.

Creating a new date (new Date(2019, 1, 0)) with the day parameter set to 0 will set it to the month's last day.

function months(month, request = 1, year){
   if(year === undefined) year = (new Date()).getYear();
   const d = new Date(year, month, 0);
   return request === 1 ? d.toLocaleString('en-us', { month: 'long' }) : d.getDate();
}

const res0 = months(5);
const res1 = months(1,0);
const res2 = months(2,0);
const res3 = months(3,0);

console.log(res0, res1, res2, res3);
kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
0

Explanation of the Unexpected Result

The reason this code returns undefined is because you have an unhandled case that doesn't have any return value. Every if statement comes with its own else statement return false. So there is no problem there. However the switch statement doesn't handle the default case. This is the only place that doesn't have a return value so this must be the problem.

The problem occurs with a string input for the first number, since it passes the if statements, but doesn't match any switch case.

console.log("'3' <= 12 //=>", '3' <= 12);
console.log("'3' >= 1 //=>",  '3' >= 1);

console.log("'3' == 3 //=>",  '3' == 3);
console.log("'3' === 3 //=>", '3' === 3);
//                ^ used for switch comparison

This means that if you run your function with inputs like months(3, 1) //=> "March", whereas months('3', 1) //=> undefined. Convert the string to an integer first to correctly match one of the cases. This is due the fact that switch cases use a strict comparison.

After your edit this becomes even more clear, since we can see where the data is coming from.

var month = prompt("Enter an integer from 1 to 12 inclusive, representing a month of the year");
console.log(month, typeof(month));

Alternative Solution

With the explanation of the unexpected result out of the way. Let's have a look at some code that produces similar results.

var monthsByNumber = {
    1:  { 1: "January",   2: "31" },
    2:  { 1: "February",  2: "28" },
    3:  { 1: "March",     2: "31" },
    4:  { 1: "April",     2: "30" },
    5:  { 1: "May",       2: "31" },
    6:  { 1: "June",      2: "30" },
    7:  { 1: "July",      2: "31" },
    8:  { 1: "August",    2: "31" },
    9:  { 1: "September", 2: "30" },
    10: { 1: "October",   2: "31" },
    11: { 1: "November",  2: "30" },
    12: { 1: "December",  2: "31" }
};

// This allows you to access the object attributes with either
//   a string or a number.
console.log("monthsByNumber[1] //=>",   monthsByNumber[1]);
console.log("monthsByNumber['1'] //=>", monthsByNumber['1']);

// Introducing this into the function would look something
//   like this.
function months(month, request) {
    // Normally you would define monthsByNumber here, but
    //   in this case I needed it in my demonstration
    //   above.
    
    // Use an empty object if it can't find the month.
    month = monthsByNumber[month] || {};
    return month[request];
}

// As you can see below this works with both numbers as well
//   as strings.
console.log("months(1, 1) //=>",     months(1, 1));
console.log("months('1', '2') //=>", months('1', '2'));
console.log("months(32, 1) //=>",    months(32, 1));

The code above does the same as you would expect in your current months function. With the only change being that undefined is returned in case of invalid input. Which to me makes more sense than returning false. If I would ask you to give me the name of the 14th month, the answer "I don't know" is better suited than "I can't". Which is where it roughly translate to.

I would however suggest changing the naming since the keys 1 and 2 for the month name and days respectively aren't very obvious. I would go for something like { name: 'January', days: '31' }, however this requires one of two things to change. Either the request input should also be "name" or "days", the other option is transforming the request input into the correct format. request = request == 1 ? "name" : "days". Furthermore you might also want to consider returning a normal number for the days instead of a string.

JavaScript has also a Date object build-in that you might want to use to account for leap years and other things, but I won't go into detail about that here.

3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
0

@Prospective, I see that you are probably getting your hands dirty in JavaScript. Your sample appears to be a learning exercise. Good for you. JS is a fun language. I took your code and pasted it into a JS fiddle and did not get any errors (though I did see warnings). Of course, you did not provide the code you are using to call the month function. So, it's possible that you might be getting undefined because of the way that you are calling, or invoking, the month() function.

As others have suggested, try reducing code complexity by merging some of your if statements with either AND (&&) or OR (||) conditional operators.

var sentinel = true
while (sentinel) {
 
var month = parseInt(prompt("Enter an integer from 1 to 12 inclusive, representing a month of the year"));
var request = parseInt(prompt("Enter 1 if you want the name of the month, or enter 2 if you want the number of days in the month"));
var result = months(month, request);

if (result == false) {
 // reset
 alert("Try again but enter the right stuff this time");

} else {
 // output
 sentinel = false;

 if (request === 1) {

  console.log("Month number " + month + " is " + result);

 } else if (request === 2) {

  console.log("There are " + result + " days in month number " + month);
 }
}
}

function months(month, request) {
 if (!request ||
  request < 1 ||
  request > 2) {
  return false;
 }
 if (!month ||
  month < 1 ||
  month > 12) {
  return false;
 }

 var name = "";
 var numberDays = 0;
 switch (month) {
  case 1:
   if (request === 1) {
    name = "January";
   } else {
    numberDays = 31;
   }
   break;
  // Repeat for case 2 - 12
  // ...
  
  // Include a default case though this should no longer get hit
  default:
   return -1;
   break;
 }
 if (request === 1) {
  return name;
 } else {
  return numberDays;
 }
}
   

 

One other suggestion would be to move the declaration of the variables name and numberDays so they are above the switch statement. The JavaScript compiler will hoist variable declarations using the var keyword to the top of the function anyway. If you want to utilize more modern JavaScript (ES6), you can use the let keyword to declare variables in a block scope as you have done. Do note that older versions of Internet Explorer do not support let at all. Check out the caniuse.com site to determine browser compatability.

Another good practice, though not required, is to provide default values for variables that you return. You can then check for the default value when inspecting the return value for a function.

I'd also check for equality using the triple equals, ===, instead of ==. Triple equals (===) will not do a type conversion if for example, you pass in "1" for the month instead of 1. So, "1" == 1 is true; while "1" === 1 is false.

Another tip that might help you. When testing HTML/JavaScript/CSS, you can use an online site such as jsfiddle.net, jsbin.com, or Plunker.

iCode
  • 1,254
  • 1
  • 13
  • 16
  • Thanks for your tips, but the exercise I'm doing came with the code that calls a specific function. I'm just supposed to make a function that will work with the code provided. (edit: I added the calling code in the OP) – Prospective Jan 07 '19 at 22:36
  • Oh I see. Well, at least for me the function works. Even works with the original code. Please provide the code that calls the months() function. – iCode Jan 07 '19 at 22:39
  • I've added it above the function in the original post. – Prospective Jan 07 '19 at 23:05
  • @Prospective, you are very close. The main issue was that the switch was looking for a string, ie. "1", and no cases matched, so the function simply returns undefined. With some of my suggested edits, you've ended up with some data type mismatches. So I updated the code above to convert the user input to integers using the JavaScript parseInt() function. The parameter guards at the beginning of the months() function were expecting ints but were receiving strings. I also added a triple equals, ===, when checking the request # so there's no implicit data conversions when checking for equality. – iCode Jan 08 '19 at 14:41
  • I also added a return value to the default case of the switch – iCode Jan 08 '19 at 14:41
  • The above code snippet will run and work for month 1, January. I did not include months 2-12 for code brevity. – iCode Jan 08 '19 at 15:27
  • @Prospective did my post someone else’s answer help you with the undefined result? If so, could you mark the response with the accepted answer? Thanks – iCode Jan 12 '19 at 00:02
  • Thanks, I got it now. – Prospective Jan 14 '19 at 15:34