DEV Community

Cover image for Why variables can be accessed before declaration in Javascript?
Justin Graysen
Justin Graysen

Posted on • Originally published at justin-graysen.Medium

Why variables can be accessed before declaration in Javascript?

One of the most used and famous languages today without a doubt is JavaScript, nowadays it is everywhere, we can create web applications and systems, develop APIs on the back-end and create mobile applications.

Despite its popularity, many people don’t like JavaScript, mainly because some particularities of the language are very different from others.

One of the things that confused me when I started using JavaScript was the possibility of using variables or functions before their declarations and I believe that many people also find this a bit strange.

In this post I will try to explain how does this happen. 👇

Photo by [Tudor Baciu](https://unsplash.com/@baciutudor?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)

Execution Context

Before we talk about variables and functions, we need to understand some concepts about the JavaScript language, the first of them will be context execution.

In JavaScript a fundamental unit of execution are functions, we use them all the time, to calculate something, perform side effects (like changing the UI), reuse code or to make code easier to understand. We also know that a function can call another function, which in turn can call another function, and so on…

When a function calls another function, the code execution must go back to the position where it was called from, i.e:

Javascript code

When calling the dialog function we will call another function (in this case hello), when the hello function is finished executing, we need to go back to where it was called, i.e., inside the dialog function and continue execution.

But, have you ever wondered how the JavaScript engines keep track of all these functions running and returning to specific positions in the code?

In JavaScript there are two main types of code: global and function.

Global code

This code is defined outside of all functions, i.e. they are loose in our JavaScript.

Function code

This code is defined inside the functions.

When our code is being executed by JavaScript engines, each statement is executed over a certain execution context and as we have two types of code, we also have two types of contexts: global execution context **and **function execution context.

The most significant difference between them is that there is only one global execution context, it is created when JavaScript starts its execution. While for each function invocation a new function execution context is created.

Thus, it is through these contexts that JavaScript can handle pauses, executions and callbacks.

We know that JavaScript is based on a single thread execution model, that is, only one piece of code can be executed at a time. Therefore, every time a function is invoked, the current execution context is paused and a new function execution context is created, from which the code will be evaluated. After the function has performed its task, that is, its code has been executed, the execution context of that function is usually discarded and the previous execution context is restored.

So it is necessary to keep both contexts tracked, that is, we need one running execution context and another context that is paused. The easiest way to implement this functionality would be through stacks, called execution context stacks.

Lexical Environment

Now that we understand a little more about how execution contexts work, let’s take a look at the lexical environment.

Consider the following example:

Javascript code

In this case, we know that by calling the console.log function a new execution context will be created, but how does the log function get the value of the variable name?

This process is called identifier resolution, basically the idea is to find out which variable a given identifier refers to, the execution context does this through the lexical environment.

A lexical environment is an internal JavaScript mechanism to keep track of the mapping of identifiers to specific variables, going back to the previous code:

Javascript code

The lexical environment is consulted when the variable name is accessed, that is, in the console.log declaration.

Lexical environments are an internal implementation of the JavaScript scopes mechanism, and people generally refer to them as scopes.

Generally a lexical environment is associated with a specific code structure, it can be associated with a function, a block of code or a catch (part of try/catch) and each structure can have its own identifier mapping.

Types of variables in Javascript

In JavaScript we can use three reserved words to define variables: var, let and const. They differ in two aspects: mutability and their relationship to the lexical environment.

Mutability

If we categorize the variable declaration by the mutability aspect, we can put const on one side and var/let on the other.

All variables defined with const are immutable, that is, their value can only be set once. On the other hand, all variables defined with var or let can have their values changed as many times as needed.

Lexical environment

The three types of variable definitions (var, let and const) can also be categorized by their relationship to the lexical environment (by their scope), we can put var on one side and let/const on the other.

Using var

When we use the var definition type, the variable is defined in the nearest function or global lexical environment (blocks are ignored). Let’s take a look at the following example:

Javascript code

What can be strange with JavaScript, and confuses a lot of people coming from other languages, is that we can access variables defined in block code outside of these blocks.

This is because when we declare variables with the reserved word var they are registered in the nearest function or global lexical environment, regardless of block scopes.

Using let and const

Because of this odd behavior, in the ES6 version of JavaScript two new variable declaration types let and const have been added.

Unlike var, they define variables in the *nearest lexical environment *(it can be a block, a loop, a function, or global).

Making a few changes to the previous code:

Javascript code

In this example, you can't access the text variable outside of the for loop and you can't access the message variable outside of the function hello. Because, in both cases, it's not in their lexical environment.

Registering identifiers in the lexical environment

One of the principles of the JavaScript language is to be easy to use, so we don’t specify function return types, parameter types, variable types, and so on… And you already know that JavaScript code is executed line by line, so let’s take a look at the following example:

Javascript code

If code is executed line by line, how can we call the hello function before its declaration? The execution of JavaScript code occurs in two phases:

  1. The first phase is activated when a new lexical environment is created, in this phase no code is executed, but, the JavaScript engine visits and registers all variables and functions declared in the current lexical environment.

  2. In the second phase, JavaScript execution occurs after the first phase was performed, this behavior depends on the variable declaration type (var, let and const) and the environment type (global, function or block).

Let's take a look at another example:

Javascript code

In this example it will be logged undefined in our console, because the first step will be to scan and register the identifier for each variable with the initial value undefined. The value of the variable will be set to the second one when the code execution is actually done.

This is because variables of type var can have their values undefined and be accessed before their declaration.

Note: If the variables were defined with let or const, JavaScript will throw a ReferenceError saying that we cannot access variables before they are declared.

Conclusion

In this article we saw why variables of type var can be accessed before their declarations and how declaration functions can be called before their definitions.

We also saw some interesting JavaScript concepts such as: execution contexts, lexical environments, scopes, identifier resolution and identifiers.

Thanks for reading! Follow me in this platform to read more development content. Have a great day, see you soon! 👋

Top comments (1)

Collapse
 
smlka profile image
Andrey Smolko

In your last code snippet there is a typo - you use 'const' instead of 'var' declaration.