Use of isNan() in the School Catalogue Project

Link to project:
https://www.codecademy.com/courses/introduction-to-javascript/projects/school-catalog
Link to project walk-through video:
https://youtu.be/9p2VeKRKZ1Q

Step 5 in this project asks us to create a setter for numberOfStudents, which also verifies that the input is a number. In the walk-through video, the suggested solution uses isNaN(). I would like to raise some issues I’ve found with this and get some feedback:

  1. I think the video incorrectly uses isNaN() in the if statement’s condition, as follows:
set numberOfStudents (value) {
  if (value.isNaN()) {
    console.log('Invalid input...');
  } else { 
    this._numberOfStudents = value;
  }
}

This results in an error as I don’t think isNaN() can be used in this way, and it will get people confused e.g. https://discuss.codecademy.com/t/school-catalogue/411818/21?u=jon_morris. As @mtf also points out in this linked post, and as indicated in https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN#Syntax, the correct use of isNaN() should be:

isNaN(value)
  1. However, on testing I’ve found some issues with using isNaN(value) in the above setter. Inputs of '10' (a number as a string), null, true and false all evaluate to false, and are therefore incorrectly allowed.

  2. In his “Aside” in this post https://discuss.codecademy.com/t/setter-in-javascript-project-school-catalogue-not-doing-anything-please-help/348546/8?u=jon_morris, @mtf suggests using the unary operator + instead, as follows:
    (He explains how this works in his post)

set numberOfStudents (value) {
  if (+value) {
    this._numberOfStudents = value;
  } else { 
    console.log('Invalid input...');
  }
}

On testing, this seems to be an improvement on using isNaN(value), as inputs of false or null evaluate to false, and therefore now correctly log the Invalid input message. However, out of the values incorrectly allowed by isNaN(value), inputs of '10' (a number as a string) and true are still incorrectly allowed by +value. In addition, the number 0 isn’t allowed (as this is evaluated as false), although this isn’t really an issue, as in this particular use case we wouldn’t want numberOfStudents to be set to 0 anyway.

  1. Using typeof value === 'number' as the condition avoids all of the issues described above with isNaN(value) or +value, and only number types are allowed. So, the following seems to me to be the best solution:
set numberOfStudents (value) {
  if (typeof value === 'number') {
    this._numberOfStudents = value;
  } else { 
    console.log('Invalid input...');
  }
}

Any thoughts and comments gratefully received :smiley:

 > +true
<- 1
 >

That’s why isNaN(true) is false.

To get around +value failing for 0, we can use isNaN()

 > value = 0
<- 0
 > isNaN(+value)
<- false
 > value = '10'
<- '10'
 > isNaN(+value)
<- false
 > 

We see that using isNaN() in combination with the unary operator returns valid results in all cases except false (which coerces to 0).

As mentioned above, 0 is not likely to be considered a valid input, and further to that, neither would be any negative numbers.

if (+value > 0) {
    // only non-NaN greater than 0 passes
}

The equivalent to the above using the typeof operator is,

if (typeof value === 'number' && number > 0) {

}

So dialing up the condition to greater than zero brings the unary operator approach out to the front for its sheer simplicity.

With +value I’d incorrectly stated that this doesn’t allow an input of '10' (a number as a string). I’ve now edited my original post as follows:

Surely, we also want to exclude inputs of numbers as strings, and only allow the number data type for consistency and ease of further data manipulation? If we do, then the best solution (even though more verbose) seems to be:

if (typeof value === 'number' && value > 0) {
  // code block
}

This excludes numbers as strings and the boolean true (the latter still being allowed by (+value > 0) even if we decide that numbers as strings are fine to include).

Not necessarily. What if the inputs come from prompt()?

As for true being accepted, it amounts to 1, which would raise an eyebrow when we see the numberOfStudents equal to 1. Anytime we can accept numbers as strings it cannot be all bad.

Ultimately, refined code will likely use try..catch to rule out invalid inputs. Both of our methods would be set aside in that event.

1 Like