Forgetting to declare variables
Here we have a variable, which we've named message, it holds the text 'hello world', and it was created using the var keyword:
var message = "hello world”;
So we've defined a variable exactly as we should. But what happens if we forget the var keyword and only provide the variable name? What will happen?
message = "hello world”;
If we run our code, we don't see an error, so this code ran successfully. And therefore a value called message was created, but was it as a variable?
Problems with the global object
In fact, it was added to something called the global object. The global object is something that can be accessed anywhere within our application. And this behavior can be very helpful. We're going to be working with the global object a great deal in this course and in our applications in general because it gives us a lot of useful features wherever we need them.
If our environment is a browser, you can refer to the global object with window. But note that, in the future, if you're writing JS in multiple environments, it’s better to use globalThis instead.
So here, in the browser, can see our global object, window, if we just console.log(window):
console.log(window); // Window
So to see that the message was put on the window, we can say:
console.log(window.message); // "hello world"
And we get the text message was set to, hello world.
Note that when working with the global object, we often don't have to reference it by name.
So we can omit window entirely...
console.log(message); // "hello world"
And we still get message's value.
So this is the important thing if we forget the var keyword when creating a variable--even though we can access it like it's a variable it isn't not a variable. It's a property of the global object.
message = "hello world"; var message = "hello again";
How do you know which value you're using: the property or variable?
The problems are even more apparent if we use a name that already exists on the global object. For example, a function that we can use throughout our program to display other developers of something is the console.log function. We can pass it any message we like:
And console, what that we just used, is also a property of the window, we're just omitting the window reference. So what if we incorrectly create a variable with the same name, console, but try using console.log, the function?
console = "hi"; console.log("hi"); // Error: console.log isn't a function
Think about what we've seen earlier with variables declared without var and try to guess what will happen when our code runs...
We get an error telling us console.log isn't a function. Why? Because we just overwrote the console property on the window object, simply because we forgot var.
How can we fix this behavior?
- Normal “sloppy” mode is the default in scripts
- On the other hand, strict mode is a mode where several pitfalls of normal mode are removed and more exceptions are thrown and can be switched on in scripts.
Using strict mode
Since we're in sloppy mode right now, let's try strict.
You can switch on strict mode for a complete file, by putting the following code in the first line. Use strict written exactly like this as a string:
If we try running our previous code in strict mode, when you try to use a variable that hasn’t been created:
"use strict"; message = "hello world"; // Reference Error
...we get a Reference error that stops the program, telling us the variable we're trying to use isn't defined. And this is exactly the behavior we want. We want this error to stop our program to prevent mutating the global object and potentially overwriting existing properties on it.
use strict is helpful, but doesn’t fix everything
So know that strict mode helps with variables and a lot more quirks of the language, but there are still some issues when working with var that to be aware of, like hoisting:
What is hoisting? Let's take another example. Say we have a valid variable, age, initialized to 26:
var age = 26;
So let's look at what age contains by logging it to the console:
var age = 26; console.log(age); // 26
Works like we would expect, but what if we tried to log age or access it before it was created? What will happen?
console.log(age); // undefined var age = 26;
We don't get 26, as before, but we get the empty value of a variable, undefined. So what's happening?
Hoisting is the way JS developers describe the strange ability to access a variable before it's been created. When the JS engine, the thing that runs our code, looks at our code, it's as if the variable's declaration has been hoisted or lifted up to the top of the program, and nothing else, not the value the variable is set to. To rewrite our program in terms of what the engine sees, it looks like this:
var age; console.log(age); // undefined age = 26;
...where the declaration is brought to the top or hoisted to the top of the context its running it, which is known as its scope.
That's why we get the default, empty value of the variable, undefined when we console.log it.
This doesn't make any sense to be able to use something before it's been made, so we would hope that this causes an error in strict mode, but it doesn't.
So if strict mode fixes some of the problems with var, but not all of them, including the problem of hoisting, what can we do?
We'll cover that in the next section...