DEV Community

Cover image for What is Lexical Scope in JavaScript?
Ekaterine Mitagvaria
Ekaterine Mitagvaria

Posted on • Edited on • Originally published at Medium

What is Lexical Scope in JavaScript?

Lexical scope also known as static scope is something you will hear about many times during your JavaScript journey and it's important to understand what it means exactly.

If you have not already, make sure to read my post about variable declarations to understand how scoping works as well as execution context as this will help you to understand the lexical scope much faster (which I also briefly explain there).

What is theĀ scope?

Scope in JavaScript refers to the availability of variables or functions in different parts of the code. Parts of code means some block or part of the code where the variables or functions exist.

Imagine that you are variable. Your apartment where you live is your scope. The area outside your apartment, for example, the building, is another scope. The building scope is not only your scope anymore as different variables, like you, share this scope. Another scope that includes the building or apartment scope is the street where the building is located. As a result, your apartment scope is separated from the street scope and whatever happens in your apartment, stays in your apartment. In other words, scope is a box in another box in another box another box where each box has its scope.

Scope types

The top-most box is the global scope, and the next box inside it can be the function scope. The next scope can be again a function or a block scope.
Each variable keyword acts differently depending on the scope. Some variables can be accessible outside the scope they are located in. Others are locked inside the scope and you cannot access them outside their scope.

Scope types

Global scope

Global scope is the top-most scope and where the scope starts. It is the environment that is visible to all other parts of the code. For example, when you start creating different variables at the very top of yourĀ .js file, these variables are global.

Function scope

Function scope is the environment of the function. When a variable is created inside the function, we say it's function-scoped. This means that this variable cannot be accessed outside the function scope. Each function has a local scope as well. One can also have a function inside another function and in another function. The very top function has its scope, another function inside it has its scope, local scope, and the third function inside the second function has its local scope. In short, every function has its local scope.

Block scope

Block scope is the third scope environment which doesn't let created variables go outside its scope as long as this variable is block-scoped.
Block scope is the code inside the if-else conditions, switch statements, or loops like for and while.

What is the scopeĀ chain?

As the name suggests scope chain is a chain of scopes! Remember the example about functions inside functions? Let's say, we are trying to console log a variable inside the most deeply nested function. The JavaScript engine will check the local scope where the console log was called. It will check if the variable exists there. If it's not there, it will go up to the closest function and check the variable existence there.

If nothing is found again, it will go up to the next upper function, if any, and check whether the needed variable is there. This search process is called the scope chain, so it's the "search" process in the chain of scopes connected to each other.

Scope

Let's visualize how exactly the scope works in the code above.

Scope

In the code above, when we call the parentFunction inside it is declared a variable and then called innerFunction. Inside the innerFuntion we again declare a variable and call another function, innerInnerFunction, where we want to console log different variables. The first console should log the variable declared in the global scope. However, the JavaScript engine is not going to take the variable directly from the global scope. It will check the local scope first and try to find it there. In other words, it will look for a variable in the nearest area and only then move further. In our case, it will move up to the next function and search there, then again move up and search again until it reaches the global scope and finds the variable we need.

The exact same process will happen in the second console log, for parentFunctionVariable. It will keep going up the scope until it finds where this variable was created.

What is a lexicalĀ scope?

When it comes to the scope chain, the inner function can always access its function scope, so the scope chain can go upwardsā€Š-ā€Šfrom child to parent.
However, the parent function may not have access to the inner function so the function scope cannot go downwards, it always goes up only!

This process or the ability of the function to be able to access variables of the parent is called lexical scope. In other words, the inner child function is always lexically bound to its parent and can always access its variables.
Lexical scope in this case is the scope where the target variables were created. You can call a variable in one place but declare it in another place, in our example in the parent function.
What matters is where the function was created, not where it was invoked (called). The moment the function is created, it captures its outer environment. This is the same moment when it's decided which variables it can access.

Why scope chain cannot go downwards?

As I mentioned lexical scope is all about the scope chain going up and up only. If you have read about the execution context already, you learned that when we create variables, they are saved inside the variable object so we can reference them for later use. Also, when you create variables there can be two types of contexts where they are saved. They are either saved globally, or they are saved in the function execution context. Function execution context is created when you create a variable inside a functionā€Š-ā€Šso each function has its context.
When you create variables inside a function they cannot always be accessed outside of it as they are function-scoped.

Scope chain

Try to analyze the code above and guess the results.
I created three variables globally and added the same variables with different values in every function scope. Will there be any errors because I am trying to change variables like const?

Scope

There will not be errors and we will see all the variables being logged without issues. Why? Because every variable is enclosed in its function scope and doesn't go outside of it. The chain started from the most inner function but JavaScript found the values that exist inside it and has no need to search for values to show them in the console log. If I skipped creating variables in the most inner function, which values would it take? Here is the changed part in the parent function, I removed the variables in the innerInnerFunction:

Scope chain

Here is what happens. First, the search will start in the local scope of the innerInnerFunction however once there is nothing found, it will go up to the next scope and search for variables there, simple as that. The lexical scope of the function where we skipped variables is its parent function. In other words, it has access to its parent variables.

Scope chain

Conclusion

In conclusion, lexical scope in JavaScript refers to the ability of an inner function to access variables and functions defined in its outer function or parent function, but not the other way around. This is because the scope chain can only go upwards, from child to parent, and not downwards. The inner function is always lexically bound to its parent function, allowing it to access its variables and functions, which were declared in the parent's scope at the time of the inner function's creation.

Top comments (0)