Photo by Scott Webb from Pexels
The scope of a variable or a function is the part of the code in which it is available. Working with variables and scope comes intuitively to most developers. We have some mental models that help us understand when something can be off limits.
Scope is the visibility of functions and variables in the different parts of your code during runtime
As you can see in the example, even though the
global variable is assigned a different value inside the function, it is only retained in the boundaries of the same function. Outside of it, the variable has a different value — the one declared in the global scope. We also won't get an error for using the same variable name.
Here we can see that the
inner() function will have access to the variables declared in its parent function -
fn(). Whenever we need a variable inside a function, the engine will first look for it in the scope of the current function. Then it will go one level up in the function containing it. If it doesn't find it there it will continue to go up until it reaches the global scope. If the variable is not found there we will get a
var. When you do this the engine will try to look for the variable bubbling up to the global scope. If it doesn't find it there it will create a global variable for you.
As a rule of thumb, avoid poluting the global scope. If a variable is meant to be globally used then declare it in the global scope so your intentions can be clear. Otherwise keep it inside the scope it is used in.
The code above will log the string
"working" even though the function is called before it's declared.
The common explanation that is given for this behaviour is that function and variable declarations are pulled to the top of their scope. So when you try to access them they have already been declared. To the example above will actually become:
Variables are also hoisted but in a different way. Only the declaration of the variable is “pulled” to the top. The value assignment will stay where it is. In other words, we can’t access the value of a variable the same way we can call functions.
This is how the above code will look after the variables were hoisted to the top:
This is why we need to be careful when we are using function expressions.
Again, only the declaration is pulled to the top while the actual assignment of the function as a value will stay where it is. So when we try to call
test as a function we will get an error.
In ES6 we got two new variable declaration keywords —
const. The main difference between them and
let is that variables declared with the ES6 keywords are block scoped. This means that they are available only in the code block they were defined in. A code block is separated by curly braces.
Since we are discussing scope, it’s important to note that variables created with
const are not hoisted. This means that they definition is not pulled to the top like variables declared with
One way to make sure that your code is free from reference errors is to make sure that you are using only
const for variable declaration.
So, hoisting is actually a mental image to help us illustrate why we can access functions and variables before they are defined. The common explanation of hoisting is just a picture of how code is reorganized before execution. When the engine is actually executing our code our function and variable declarations are no longer there at all. They have already been declared in a previous run.