What is Lexical Scope in JavaScript?

What is Lexical Scope in JavaScript?

Lexical scope aka 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 also 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 personal scope. The area in the building you live in but outside your apartment is also another scope but it’s not only your scope anymore as different variables, just like you, share this scope (for example, elevator). Another scope that contains the building scope or apartment scope can be 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!

Another simple example is a box in a box in a box in a box where each box has its own scope.

Scope types

Remember a box in a box in a box example? The very first box in this example is the global scope, the next box inside it is the function scope and another box inside the second box is the block scope.

Each variable keyword acts differently depending on the scope. Some variables can still be accessible outside the scope they are located in while others are stuck inside the spoke and you cannot access them outside their scope.

Global scope

Global scope is a top 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 though 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 also has its own scope, local scope, and the third function inside the second function will have its local scope.

Block scope

Block scope is the third scope environment which also 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 hat local scope 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 will 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 that are connected to each other.

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

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 tries 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 find 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 not called. You can call a variable in one place but declare it in another place, for example, the parent function.

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 own context.

When you create variables inside a function they cannot always be accessed outside of it as they are function-scoped.

Try to analyze the code above and use the previous example. What do you think will happen in this case if we try to console log all variables?

What I changed this time is that I have one global variable like before but I added two more variables to the global scope that are also repeated inside the function. Next, I also try to console log the variable that I created inside the function.

Let’s try to understand what is going on here. When we try to console log variable that was declared outside the function everything works fine however when it comes to the last console log it throws an error. Why? Because there is no upper scope and the variable we need it’s inside the function. That’s why we receive a ReferenceError.

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.