Scope and guessing game0:00
I got a haircut! And you know what that means? Absolutely nothing. But we're going to talk a little bit about scope. Now we're not going to get into the nitty-gritty because you already have a good understanding of what scope is. You know what global scope is, what functional scope is, and that's it. Really the only difference in JavaScript is how we can access those variables or the things that are defined in levels of scope. There's also different ways that we can create variables, and that affects the scope of those variables. So we'll touch on all of those things. And we've done a lot of theory, but I think let's do something a little fun, like a game. A game where we will guess a secret number. And we don't really want to hard-code this number because we want to be able to guess it. So we're going to create a random number. Now Math is an object given to us by the JavaScript language. So this
Generating random numbers0:50
want to hard-code this number because we want to be able to guess it. So we're going to create a random number. Now Math is an object given to us by the JavaScript language. So this is built in, we can use it, and it provides a lot of methods to do, well, a lot of things. One of those is to generate a random number. Now this is going to be a number between 0 and 1. We want to work with just whole numbers. And ideally, you know, we could just work with numbers between 1 and 10, you know, as far as guessing is concerned, just to keep things a little simple. So what we want to do then, since this is going to return a decimal number between 0 and 1, the first thing we should do is multiply it by 10. That way we have something in the ones position. But still, we end up with a decimal number. So what we could do is use the Math object again, because there's this floor method. Basically, it's going to, well, round down. So if we have 1.2, it's going to round
we end up with a decimal number. So what we could do is use the Math object again, because there's this floor method. Basically, it's going to, well, round down. So if we have 1.2, it's going to round down to 1. If we have 1.7, it's going to round down to 1. So it's always going to take the, let's see, the explanation is returns the greatest integer less than or equal to its numeric argument, which, okay, it's just going to round down. So that's what we need to do. But it would be possible to have 0 here. So let's just add 1. And that's going to work fine for us there. Alright, so we have our secret number. But we also want to make this a little fun and have a maxAttempts. And we can set this to whatever, I'm just going to use 3. And so then we can have a function called playGame. The idea being that this will be the function that we will call to initialize the game and we'll play with it. And we want to be able to repeatedly guess over and over up until our maxAttempts. So that's
Game loop with prompt2:42
The idea being that this will be the function that we will call to initialize the game and we'll play with it. And we want to be able to repeatedly guess over and over up until our max attempts. So that's basically a for loop. So let's have attempts. And we're going to start with 1 here. And we want to go for as long as attempts is less than or equal to 10. Or no, no, no, no, we want our max attempts there. And then we want to iterate our attempts. So here, what we want to do is prompt the user for inputs. And, you know, eventually, we will get to the point to where we will use a form, we will get that information from the form. But I think for right now, what we can do is use a function called prompt. This is provided to us by the browser like the alert function. And basically, we just prompt the user to please enter a number between 1 and 10. And then whatever they type into the prompt box is going to be saved in this input variable. But, you know, the same rule applies here as for user inputs, we don't want to trust it. So we want to be sure that we have a
10. And then whatever they type into the prompt box is going to be saved in this input variable. But, you know, the same rule applies here as for user inputs, we don't want to trust it. So we want to be sure that we have a numeric value. And we can do this in a couple of different ways. But probably the easiest thing to do is just to use the Number function. Now, in the previous episode, you know, I had mentioned that all of the types in JavaScript are essentially defined by functions. So this Number function is the function that defines the number type in JavaScript. So we could new up the Number constructor to create a number object. But here, we don't need to do that, we can just pass in a string, and it's going to attempt to convert that into a number. If it is a number, then we get the number. If it's not, then we get a value called NaN in a const. So really, that's the first thing that we need to check. If the guess is not a number, which we have a built in function to check, but we also want to be sure that the guess is greater than 1, and less than 10. So if it's less than 1 or greater than 10, then we need to tell the user to
check. If the guess is not a number, which we have a built in function to check, but we also want to be sure that the guess is greater than one, and less than 10. So if it's less than one or greater than 10, then we need to tell the user to please enter a valid number from one and 10. And that should work. Now we could make the decision as to whether or not if they provide an invalid number, does that take up an attempt? And I think for right now, yeah, we could do that. Maybe later on, we will want to, you know, be a little more lenient. But if they type in something invalid, that uses an attempt, we continue to reiterate over our loop. And then we need to check if the guess is equal to the secretNumber, then we want to tell the user, hey, congrats, you guessed it. So congrats, you guessed the number. And I think that's going to be enough for that. However, we should also provide some information as to, you know, whether the guess was too low or too high, that way we can at least provide some kind of hints. So if the guess is less than the secretNumber, then we want to write a message to the console that says that their guess is too low. And let's do this. Let's say that the guess is too low, so that then we will do the
can at least provide some kind of hints. So if the guess is less than the secretNumber, then we want to write a message to the console that says that their guess is too low. And let's do this. Let's say that the guess is too low, so that then we will do the same thing if it is too high, except that, of course, we will say too high. So that way, if they guess it, congrats, if it's too low, if it's too high. And then whenever we get out of this loop, we can write a message to the console that says that the game is over. And then we can say the number is, and then we could say secretNumber, and you guessed it. But, you know, maybe the user didn't guess this, in which case we need to be a little flexible here. So let's say this. Let's have a variable which we'll call guessedMessage. That's probably not the best thing, but we'll try to determine if the user guessed it. And I guess what we could do here, if the user does guess the secretNumber, then we can say that we would have a variable called guessed, which we will set to true. So here we could check if guessed, then we'll say that they guessed the number. Otherwise, we'll say didn't guess the number. So that here, game over, the number is secretNumber, and you will put in our guessedMessage. And then we can also include the attempts.
if guessed, then we'll say that they guessed the number. Otherwise, we'll say didn't guess the number. So that here, game over, the number is secretNumber, and you will put in our guessed message. And then we can also include the attempts. So we'll say attempts, attempts. It's a little verbose. It's a very long statement, but that's going to be okay. So now we should be able to go to the browser. Let's refresh the page. Let's open up the developer tools because we need to initialize our game. So we'll call playGame, and we will be prompted to enter a number between 1 and 10. Okay, so let's do that. 1 was too low. 5 is too low. 7 is too low. Game over, the number is 9, and you didn't guess in 4 attempts. That's not right. We had 3 attempts. So let's refresh it again. Let's play the game again. Of course, secretNumber is going to be different. So let's start with 5 is too low. 8 is too low. 9 is too low. The number was 10. Other than the attempts number being wrong, we can at least see that it's somewhat working. One thing that we can do, however, is we can cheat a little bit because since the secretNumber variable is global, that means that inside of the console, we can just check to see what that value is, and we can see that it's 9. And here it is, 9 again. secretNumber. Okay, so it's 3. So we just had 9 and 10 and then 9.
cheat a little bit because since the secretNumber variable is global, that means that inside of the console, we can just check to see what that value is, and we can see that it's 9. And here it is, 9 again. secretNumber. Okay, so it's 3. So we just had 9 and 10 and then 9. So I know it's random. At least we can see now it's random because the value is 3. So now that we know that the value is 3, let's check this out. If we do 1 and then 3, we see congrats, you guessed the numbers, but we need to break out of the loop, don't we? So yeah, we need to add that in. So not only do we want to set guess to true, but we want to break out of the loop. So once again, let's check the value of secretNumber, which is 3. Is this random? I'm not sure, but we'll play a game. We'll say 1, we'll say 3, and we see that the number is 3, and you guessed in two attempts. Okay, so we can see that the attempts number needs a little work in our output, but we're not going to worry about that. So in this particular case, everything's fine. If we don't guess it, everything appears to work okay, except for the attempts number. And if we do guess it, everything does work okay. So we're great. But as I demonstrated, we have access to the secretNumber here. And this is just global, which means that we could set this. We could cheat and not only just get the value of it, but we could set it. We could say, you know, let's make it 5 so that we can play the game.
Hiding globals with IIFE10:11
So we're great. But as I demonstrated, we have access to the secret number here. And this is just global, which means that we could set this. We could cheat and not only just get the value of it, but we could set it. We could say, you know, let's make it 5 so that we can play the game. We can enter 5, and then voila. But of course, we knew that. We could also, you know, change the maxAttempts so that we can set it to 1000, because if we don't guess the number between 1 and 10 within 1000 tries, there's something wrong there. But, you know, we can do this. And that's because they are globally accessible. So one of the things we talked about in the previous episode was that we can protect our code from any outside interference by using an immediately invoked function, because that is going to basically protect all of our code because it is inside of a functional scope. It's not globally available. So we can take all of our code here. We can cut it. We can paste it inside of this immediately invoked function. But then we're going to run into an issue because while we are now protecting the secret number and the maxAttempts, this playGame function is also defined inside of this outer function, this immediately invoked function. So that means we can't access it anymore. If we go back to the browser and we try to run playGame, it's not there because it's not defined, because it's not globally accessible.
this playGame function is also defined inside of this outer function, this immediately invoked function. So that means we can't access it anymore. If we go back to the browser and we try to run playGame, it's not there because it's not defined, because it's not globally accessible. So what we can do then is simply change this so that we return a function and we will create playGame as a variable here, set it to equal the return value of this immediately invoked function, which is going to be our playGame function. So now we can come back and we can playGame. And it still says undefined. Did I save the file? I didn't save the file. You got to save the file in order to see the proper changes. But if we playGame now, we can see that we can play our game. And if we tried to access the secretNumber, it is not available. But now we have an issue. Our playGame function is once again global, which also means that it can be changed. So here inside of the console, we can say playGame equals, and then we can set it to a function that, well, it simply really doesn't do anything. So if we try to run playGame now, it's going to execute that function, but it's not going to do anything because we changed what was assigned to playGame.
Protecting with const12:37
So here inside of the console, we can say playGame equals, and then we can set it to a function that, well, it simply really doesn't do anything. So if we try to run playGame now, it's going to execute that function, but it's not going to do anything because we changed what was assigned to playGame. So just like in PHP, where we want to protect the value of a variable or more specifically a property inside of a class, we want to make this constant. And making a constant is very simple in JavaScript. We just use the const keyword. So, you know, to create a constant in PHP, we would use the define function. Or if we were in a class, we would use const. It is just the const keyword in JavaScript. So we have created a constant called playGame, which means that we cannot change the value of playGame. In fact, we will get an error if we try to do so because it is a constant variable. So that's great. However, let's jump into our debugger and let's set a breakpoint right here. Line eight at the beginning of our for loop, because now whenever we call playGame, we will hit that breakpoint.
So that's great. However, let's jump into our debugger and let's set a breakpoint right here. Line eight at the beginning of our for loop, because now whenever we call playGame, we will hit that breakpoint, which means that right now the JavaScript engine is paused at that for loop. This gives us a lot of power because as we are debugging our software in the browser, we can check values of variables. We can change values of variables, which means that once again, we can change the values of our secretNumber and our maxAttempts because they are in scope right now because the JavaScript engine is paused. Let's hop on over to the code. The JavaScript engine is paused right here, which means that we are inside of this function. But this function is defined inside of this immediately invoked function, which has these two variables in scope. This means inside of the console, we now are at that point so we can change those values if we want to. And the reason why I point this out is because it might not be apparent that we can actually do this because JavaScript runs in the browser.
This means inside of the console, we now are at that point so we can change those values if we want to. And the reason why I point this out is because JavaScript runs in the browser. That means that we really lose control over the execution of it. So as we are writing our software, we want to keep that in mind. We want to be sure that we make our code as not as safe, but we want as much control as possible because someone who knows what they're doing can get into our JavaScript and change it as it executes. So we can see that the secretNumber is 2 here, but we could set it to 5 if we wanted to, in which case, we've now changed the game and sure enough, we guessed it within the first attempt. So we can go back, we can define these variables as constants as well. That way, their values will not change.
Block scope: let vs var15:41
So we can go back, we can define these variables as constants as well. That way, their values will not change. But variables that are created using the const keyword are different than variables created using the var keyword, of course, because they're constant. But it's not just that. They also have what we call block level scope. So, you know, whenever we started this series, I said that we're going to use var to start with because that better emulates what we would expect as far as variables in PHP. Because variables in PHP, especially inside of a function, are functional scoped. A const is block level scope. So a block is essentially an opening curly brace and a closing curly brace. So if we put these two constant declarations inside of this code block, they are no longer accessible outside of this code block, meaning that our code is going to fail.
So a block is essentially an opening curly brace and a closing curly brace. So if we put these two constant declarations inside of this code block, they are no longer accessible outside of this code block, meaning that our code is going to fail. If we go back to the browser, we can refresh. And if we tried to run playGame, we're going to get an error, a reference error, because maxAttempts is not defined. So whenever you create constant variables, you need to be aware of where you define them. Because if you define them inside of an if statement or an if block or an else block or any other code block, it's going to be confined just to that code block. And it's no longer in scope outside of that code block. Let's look at this. We have another way of creating a variable using the let keyword. So right here, whenever we start our for loop, I'm going to change the attempts variable to be declared with let.
We have another way of creating a variable using the let keyword. So right here, whenever we start our for loop, I'm going to change the attempts variable to be declared with let. So let creates a variable with block level scope. So that means that this attempts variable is only accessible inside of the for loop. So once the for loop exits and we try to use that down here, whenever we specify the attempts in our final message, we're going to get an error because attempts is not available there. So what we would have to do to fix that would be to define let right here. We can say attempts equals one. Then we can have attempts and then our condition and our increment. So now the attempts variable is defined inside of the function, meaning that it can be accessed and used anywhere inside of that function. That also means that's right here where we guess the secret number.
So now the attempts variable is defined inside of the function, meaning that it can be accessed and used anywhere inside of that function. That also means that's right here where we guess the secret number. You know, we have our congrats message and then we set this guest variable to true. I created this variable using the var keyword very specifically because by creating it using var, I could use it anywhere within the function. If I created it with let, well, it is only usable inside of this if block. It's not even available inside of the else if or the else block. But by creating it with var, we can use it anywhere. So then the question becomes, what is the best way to create variables? Do you use let? Do you use var?
Do you use let? Do you use var? Of course, if you need a constant, use the const keyword, but also be aware of where you define it because it only exists within the block that it was created in. But as far as let and var, I'm not going to say it doesn't matter because it matters. It matters because they have technical differences. But ultimately, it's a variable. Create it how you want to create it. Personally, I use let because I use a lot of other languages that have block level scope. So it's easier for my brain to use let because I'm already kind of in a mode of block level scope. But if you're more comfortable using PHP's scope, or at least thinking in terms of PHP's scope, then use var.
So it's easier for my brain to use let because I'm already kind of in a mode of block level scope. But if you're more comfortable using php's scope, or at least thinking in terms of php's scope, then use var. There is no wrong or right way of going about it.
