Deep JavaScript Foundations, v3

Coercion Exercise Solution

Kyle Simpson

Kyle Simpson

You Don't Know JS
Deep JavaScript Foundations, v3

Check out a free preview of the full Deep JavaScript Foundations, v3 course

The "Coercion Exercise Solution" Lesson is part of the full, Deep JavaScript Foundations, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle live codes the solution to the exercise.

Preview
Close

Transcript from the "Coercion Exercise Solution" Lesson

[00:00:00]
>> Kyle Simpson: Okay, welcome back from the coercion exercise. Hopefully you found that an interesting challenge. Let's start, again, remember the read me says we want an is valid name function. So we'll start by defining isValidName(). It needs to take a name, and it needs to assert several things. First off, that it is a string.

[00:00:24]
Secondly, that it contains at least something that's not only white space, and the stuff that it contains that's not white space has to be at least three characters long, okay? So first off, we wanna make sure that the typeof name == "string". Here I'm using the double equals with the type of operator because we know that the type of operator always returns strings.

[00:00:50]
And we know that it always returns non-empty strings, so we know we're safely out of the corner cases, if you will. So if (typeof name == "string"), and,
>> Kyle Simpson: We also wanna make sure that we don't consider any only white space that may be in the string, in terms of our length check, that is.

[00:01:17]
So one built-in way to do that with JavaScript strings is the trim method. So we can say if name.trim(), which trims off any weight space from either side, and if what is left is at least of length three, then we know we have a valid string.
>> Kyle Simpson: Did I use greater than, or greater than or equal?

[00:01:46]
Yeah, I'm sorry, >= 3, okay? In that case, we wanna return true, and otherwise we can return false. Now, you could simplify this a little bit to simply return that expression if that's your preference. You could not have an if statement here. Just being illustrative of the decision making that we make, which is are we in a success condition?

[00:02:08]
Great, we return true, otherwise we're not, and we return false. So if we just test this right away, we should get that test to pass, and we should get these six tests to pass, and everything else should fail. I don't wanna get errors, so I'm gonna just define an hoursAttended() and have it return nothing for us.

[00:02:32]
So all the rest of those should fail. So let's try,
>> Kyle Simpson: Over in the console. Again, you could run that via Node, if that feels more comfortable to you. But let's run it over here in the console, and let's see if it prints out the results we're expecting.

[00:02:50]
So the first test returns true, which is good, and then we have several failures. Four failures, and then we have one, two, three, four, five, six successes, so we see that is valid name is passing our test three, okay? That's good progress. Let's move on to hoursAttended. Now, this one was a little bit more complex but not significantly so, it takes in two parameters.

[00:03:15]
Remember we're gonna call those attended, meaning the number of hours that you attended a workshop, and the length of the workshop. Now, we're trying to make sure that what was inputted is valid, that you attended not more hours than the workshop actually attended, you don't wanna get extra credit there.

[00:03:30]
So the read me says we wanna make sure that these are either strings or numbers, and that regardless of which one they are we're gonna treat them as numbers. So if the attended is a string then we wanna turn it into a number, okay? So first off we could say if the (typeof attended == "string").

[00:03:59]
And you recall that it's going to, I'll just double check here. Yep, we recall that we need to make sure that we're not getting an empty string coerced into a zero, cuz that's not the same thing as somebody typing in zero here. So that's a little corner case that we wanna take care of.

[00:04:20]
So we're gonna say if type of attendant is a string, and we're gonna use our little friend trim again. And attended.trim() is not equal to empty string. So we don't want any white space only or empty strings to fit in here. But if we have a non-empty string, then let's go ahead and try to make it into a number.

[00:04:44]
So here we could say attended = Number(attended). Now, here's where I diverge a bit from standard crowd that, for example, like static typing, cuz they don't like to reassign a variable to its new type. I think this is a perfectly valid example of reassigning variables with a different type, when you are explicitly changing the type for some purpose, like we are here.

[00:05:12]
So that's one of the reasons why I don't like it when tools complain at me about reassigning over types. Okay, so we're gonna do the same thing that we just did for attended, we also wanna do that for the length variable. So I will just duplicate that and change the variable to length.

[00:05:33]
We could probably factor that out into a function, but [SOUND] who cares? Okay, so now we know that if it was passed in as a string, it has become a number. If it was a number, it's still a number. But we don't know that you might have passed in something like null or undefined, so we still actually need to check that both of these are numbers before we do something.

[00:05:54]
So our check means to first say, if typeof attended == "number" && typeof length == "number". If either one of those is not true, we're gonna bail out, right? So here is our if statement, and then we're gonna bail out, and that means we end up returning false.

[00:06:18]
This didn't pass the validation. But there's more that we need to check besides just the fact that they are numbers. If you recall in the read me, it said we wanna make sure that they're treated as numbers. They need to be 0 or higher. So we need to check not only that they are numbers, but we need to also see that attended >= 0, and length >= 0.

[00:06:45]
The read me also says that they need to be whole numbers, meaning they can't be like 3.14, or 9.1 as in the test cases. So if you did a quick check on mdn you might have found that there is a utility built into JavaScript specially for this. And it's called Number.isInteger, that tells us if we have a thing that is, yeah?

[00:07:11]
>> Speaker 2: I mean, I think you actually casted it as a number in the first part, right?
>> Kyle Simpson: Yes.
>> Speaker 2: So they're are always gonna be numbers afterwards probably [CROSSTALK]
>> Kyle Simpson: They are, because if I pass in a null here then it's not gonna go into this clause and it's gonna still be null here.

[00:07:24]
>> Speaker 2: Uh-huh.
>> Kyle Simpson: So that's why I have to check to make sure that it's actually a number.
>> Speaker 2: Okay.
>> Kyle Simpson: Right, cuz we want to allow strings and numbers, but if you pass in anything else, you're gonna fail the validation, if you will. Passing a null fails the validation.

[00:07:41]
Okay, so we're gonna check to make sure that attended is actually an integer. And we're gonna check that,
>> Kyle Simpson: Length is actually an integer. That really literally just says doesn't have any fractional component on it, basically what it's doing, right? So checking that it's a whole number, all right?

[00:08:03]
And then the final thing that the read me says is that attended has to be less than or equal to length. Well, since we definitely know we're dealing with well formed numbers at this point, we don't have any NaNs, or infinities, or any of that other stuff. Then it's a very safe check for us to say, attended <= length.

[00:08:25]
>> Kyle Simpson: So we've restricted the overall surface area that could have possibly gotten us into corner cases. Into what is a fairly straightforward set of checks to validate that what we're passing in is what we want to be passed in. And we're eliminating any of those corner cases, like somebody passed in an array with a number in it or anything else bonkers like that, okay?

[00:08:52]
If we have passed all of these checks then we can return true, and if that didn't pass, then we can return false. Same thing as before, we could now refactor that to a single return statement. I just wanted you to get the point of how we build up those test cases, okay?

[00:09:04]
So let's now test this code over in our console, and we should get all trues now, so run this code and we get all trues, yay. All right, so we've written a couple of validator functions, point being wanted to get you familiar with the idea working with these primitive values and the ways that they can be coerced.

[00:09:33]
And still not go off the rails into those crazy corner cases. Protect yourself against those corner cases. There are of course lots of ways that you could have implemented either one of these functions. Instead of doing a .length or checking for something, you could have used a regular expression.

[00:09:50]
But the spirit of this was to use what we know about primitive types and about the checks that our coercion say, okay?

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now