Functional-Light JavaScript, v3

Immutability Solution

Kyle Simpson

Kyle Simpson

You Don't Know JS
Functional-Light JavaScript, v3

Check out a free preview of the full Functional-Light JavaScript, v3 course

The "Immutability Solution" Lesson is part of the full, Functional-Light JavaScript, v3 course featured in this preview video. Here's what you'd learn in this lesson:

Kyle live codes the solution to the exercise.


Transcript from the "Immutability Solution" Lesson

>> Kyle Simpson: Let's talk about the solution to the immutability exercise. Number one we need to define a pick number that is going to take the current list of lucky lottery numbers and add a new lottery number to it if it hasn't already been included. So I'm going to pass in for sure, the lucky lottery numbers, the current numbers list.

We know that if we're going to do any mutations to this list we need to avoid changing that list. So I'm immediately going to think, I better go ahead and make a copy of it before I do any changes to it. And we know at the end, we're definitely going to be returning that numbers list.

So down here in our while loop, our pattern is going to be to call pickNumber with the current list and get back a new list. So the way we're going to do that is just to say luckylotteryNumbers = pickNumber(luckylotteryNumbers). And you recall that we talked about from a read only data structures perspective, line 15 in isolation from seeing how pickNumber works, could confuse someone into thinking that it might be mutated in some way.

So what we should do just for good measure is to use Object.freeze around it.
>> Kyle Simpson: Putting Object.freeze around the luckyLotteryNumbers value prevents it from being modified and also tells the reader you don't need to worry about it. It's not getting modified. It's a little bit of a moot point here since we're reassigning anyway.

But it's just for good measure to get practice with the idea that we shouldn't pass in data structures and leave it up to the reader for them to guess what's going to happen. We should be as clear as possible. While we're on the topic of doing this reassignment, that's the reason I'm going to leave this as a var declaration because I do want to be able to reassign it each time.

And then we have the question about, what about this number six here? You can use the number six there, but generally, when there's a magic number inside of a program, somebody's going to ask, how'd you come up with that number? So, maybe what we ought to do, is use a constant like NUM_COUNT.

I don't know that may not be a good name for it but let's just go with that. We're going to say NUM_COUNT = 6. And you'll notice here I'm going to go ahead and use the the const keyword. Because in this particular case we are assigning a thing that is already an immutable value, and it is serving the purpose of a constant, which is to be a semantic placeholder for an otherwise literal value.

So in that case that's exactly what const should be used for. That makes sense. We don't necessarily want to use const for its ability to be not reassigned but rather to use it for the semantic signal. Which is this semantic placeholder for this particular value. Okay let's go back to pickNumber we know we're going to need to grab a lottery number and then check to see if it's in.

And as soon as we might get a new number like calling lottery number here what we should be asking ourselves is that makes pickNumber an impure function. As soon as we call that from inside of here it makes picknumber an impure function. So what if instead of doing that we were to pass in the number to be used, and that I think is going to end up being a better way of going about it.

So what we're going to do is generate, and I'll move this to a separate line. So it's a little easier to read. We're going to generate our new lottery number to insert here.
>> Kyle Simpson: And pass that in. At this point, pickNumber might be a slightly wrong name for this function.

We might come up with some other name if we were really creative like, insert number or record lottery number, maybe we'll call it recordNumber.
>> Kyle Simpson: Just to be slightly more semantic with what its purpose is now. Okay, so we are passing in the lottery number that we have generated and we're passing in the list of numbers.

We need to decide whether that number should be inserted into the list or not. So we need to say, if the numbers.include(num), and we need to say only if it doesn't include it. So I'm going to negate only if it's not included in the current list of numbers.

Do we want to insert it? Because we have a local copy of this array, it's okay to mutate. We can say numbers.push with the (num). And then we need to do a sort on this. So you might call numbers.sort. There is a little bit of a problem and it hinted at this in the readme.

There is a problem with the build in sort method on JavaScript arrays. Which is that it sorts alpha numerically. And if you ran it you might accidentally see something like the number nine showing up in front of the number ten. Or something like that because of the alphanumeric versus numeric sorting.

So to force numeric sorting, we need to provide a custom comparator. I'm going to say, a custom comparator called ascending. Where I take two values and the way this comparator works is it needs to return negative 1 if X is less than Y or something greater than 1 if Y is greater than Y, X or zero if they're equal.

It turns out there is a nice little mathematical trick for doing that. Instead of writing out the if else, the three if else conditions. There is a nice little mathematical trick which is if we want to do numeric sorting, we can say X- Y. Because if X is bigger than Y, then that will return something greater than zero.

If X is less than Y then that will return something less than zero. And if X and Y are equal that will return exactly zero. So that is a way of kind of short handing our numeric comparator. Now we've got a number being pushed in, we are sorting it and we are returning the numbers.

So, again we only sort when we have inserted a new number. Let's look back at our while loop and just convince ourselves that the while loop is still going to work correctly. Basically what happens if the number has been included we passed in a number that was already there.

We end up returning back a numbers that hasn't even been changed. So maybe what it would make sense to do is not even do the copy of the numbers array unless we know that we're going to modify it. Another way of doing a slice and then a push we could have combined these two operations we could have said something like.

And an array where we take in the current list of numbers and add num on to the end. That's maybe a little bit more declarative than doing .slice and .push. So what's gonna happen with our while loop is that it's going to keep going. And if luckyLotteryNumbers length hasn't changed, it's just going to loop again and try a new generation for a number.

And it's gonna keep doing that until it's been able to insert in six unique numbers and then we'll definitely have a sorted number at the end. If I take this code and I move it over here and try to run it what we should get. Is a list of six lucky lottery numbers.

All right, there is your lucky lottery numbers for the day. If any of you go win a billion dollars, I expect 10% of it, okay? [LAUGH]

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