What is scoping?

In programming, when we talk about scoping, we talk about the accessibility and availability of variables in a script. Something along these lines:

At what places is this variable accessible?

Scoping isn't a new concept in JavaScript; it has been and is there in other languages as well together with variables. Understanding it is of immense importance as it prevents unrecognisable errors creeping into our programs.

So what actually is scoping? Going technical we can define scoping as follows:

Scoping is the measure of the availability of a variable at different places in a script

This definition might sound complicated if you have no previous knowledge of variable scoping. However if you do have then making sense out of this would be a piece of cake!

Coming back to the definition, let's explain what it really means.

Scoping tells some information about a variable. That information is: where is it available in a script - is it available outside this block of code, is it accessible within functions, or is it available throughtout the whole script.

This availability factor of any variable is affected by where is it declared. For instance, if it is declared inside a function, it will be available only within that function. Only the declaration of a variable governs its scope. NOT its assignment, not any internal keyword nothing. Remember this!

If you don't know what is the difference between variable declaration and variable assignment then you shall definitely consider reading this chapter on JavaScript Variables.

For example consider the following code:

function logger() {
    var x = 10;
    console.log(x);
}

logger(); // logs 10
console.log(x); // logs undefined

We have a variable x defined inside a function. Only when we call the function, x successfully gets logged with the value 10. However logging x outside the function (at line 7) outputs undefined.

The reasoning to why we get two different logs in the console with exactly the same variable lies in the concept of scoping. The variable x here is said to be accessible within the function logger only - outside of it, it ISN'T ACCESSIBLE!

Despite the fact that this example is really simple and basic, this is just what scoping is - there isn't anything difficult about it.

JavaScript comes with three kinds of variable scopes:

  1. Global scope
  2. Local/Function scope and
  3. Block Scope

Let's start by giving basic explanations for what each scope relates to, and then move on to mix up these to form some complicated scopings.

Each scope targets differing regions of a script as we will see next. Once you get the hang of all these three scopes you will for sure conclude with saying that woah, scopes are really easy!

Global scope

Global scope defines accessibility throughout the entire script.

Try to relate the meaning of the word "global" with this.

A variable that is declared using the var keyword, and is not within a function, is a global variable. Such a variable is available everywhere - inside functions, inside blocks, in other scripts etc.

Following we create two global-scoped variables - x and str:

var x = 10;
var str = "I am global";
// x and str are accessible here

function logger() {
    // x and str are accessible here
    console.log(x); // 10
    console.log(str); // "I am global"
}

console.log(x); // 10
console.log(str); // "I am global"
// x and str are accessible here
Just remember global means everywhere. If a variable is global-scoped then it is right away accessible literally everywhere!
In the definition above we said 'declared using the var keyword' since there is yet another way to create variables in JavaScript and that is using the let keyword.

Local scope

Local scope defines accessibility within a function.

A variable declared within a function is said to be locally scoped for that specific function. It would nor be available in the global scope and neither in the local scope of any other function - only WITHIN the function it is declared in.

A variable locally scoped exists only for the time being of its function i.e as soon as the function exits the local variable is DELETED.

Following we create two local variables inside the function sum() - x and y:

function sum() {
    var x = 10;
    var y = 5;
    // x and y are available here
    console.log(x + y); // 15
}
sum();
// x and y are NOT available here
console.log(x + y); // undefined

They can be accessed from within the function sum only and not outside of it. This fact is illustrated in the lines 5 and 9: the log made within the function (line 5) gives 15 whereas the one outside it (line 9) gives undefined.

Local scope and nested functions

One thing worth mentioning over here where some people tend to get confused is that a local variable is completely accessible in sub functions of the main function where declared.

What this means is the following:

function sum() {
    var x = 10;
    var y = 5;
    // x and y accessible

    // a sub-function of the main function sum
    function logger() {
        // x and y accessible
        console.log(x + y);
    }

    logger();
}

Just like before we have the same sum() function here but this time instead of directly calling console.log(), we call it inside a sub-function logger().

Since logger() is defined within sum() it turns out that the variables x and y are available in it also. And similarly if we had more nested functions within logger(), the variables would even then be in scope.

A variable local to a function is available everywhere within that function.

Block scope

Apart from global and local scopes, variables in JavaScript can also have block scoping.

Block scoping defines accessibility within a block of code. A block is denoted by the { } curly braces.

Block variables are created using the let keyword. We will discover this keyword in detail in the next chapter so for now just consider how it works at a basic level.

{
    let x = 10; // block scoped
    console.log(x); // 10
}

console.log(x); // undefined

Here the variable x is defined inside a block, with the let keyword, and is therefore inaccessible outside of it as shown in line 6.

Don't worry if you don't get this piece of code. The let keyword is yet to be discovered in detail.

Remember - declarations govern scope!

What is the scope of x in the following code? Local or global?

var x; // x declared

function a() {
    x = 10; // x assigned 10
}

a();

Many people think that x is locally scoped but it is NOT - it is a global scoped variable. How? Because its declaration is in the global scope - we've said this previously and will emphasise it again now that only declarations are the governing factor for scopes.

This means that even if a variable is assigned some value inside a function, but declared globally it would still follow the global scope.

A mix of scopes

Now that we know what are global and local scopes in JavaScript we can now do some experiments with both of them and see whether you can figure out the answers to our questions.

We will ignore block scopes for now since they are a concept bundled with a guide on the let keyword. Without it we can't understand much of block scoping.

Worked example

So continuing on with globals and locals consider the example below and determine what each console logs. This is worked example so even if you get stuck and aren't sure about the output we will explain everything!

var x = 10;
function logger() {
    console.log(x);
}
logger();

What do you think is the the scope of x and what is the log made in the console?

The scope of x is global and the log made in the console is 10. How? Here is the explaination.

The var x is defined outside any function and is therefore a global-scoped variable. Since global means everywhere it turns out that x is accessible within logger().

For the code below, answer the following questions:

  1. What is the scope of x?
  2. y has the same scope as that of x. True or false?
  3. z is accessible only within the function sum() or is it accessible outside it also?
(function() {

    var x = 10;
    var y = 5;

    function sum() {
        var z = x + y;
        console.log(z);
    }

})();
  1. Local scope
  2. True
  3. z is accessible only within the function sum().

Overriding variables

Uptil now we've only seen scoping examples with one or two different variables created at different locations in a script, but now we will take this to a more complex level by creating same variables with different scopes.

Before proceeding any further let's recall that:

  1. Global variables exist till the document is closed.
  2. Local variables exist till their function is executed.

And with this in mind we can now proceed to look at overriding variables at different scopes.

Go over the code below and think for a sec, what would be logged at each instance in the console.

var x = 10; // global scoped
console.log(x);

function a() {
    x = 5;
    console.log(x);
}
a();

console.log(x);

If you thought 10, 5, 5 you are doing amazing at this foundational stage!

First we log the global variable x which is 10. Then we call the function a() which simply changes the value of this variable x to 5, and thus we get 5 logged. Finally since the global variable has been changed, therefore the last statement also logs 5.

Consider the code below and guess what would be logged in the console at each instance.

var x = 10; // global scoped
console.log(x);

function a() {
    var x = 5;
    console.log(x);
}
a();

console.log(x);

If you guessed 10, 5, 10 then you made a superb guess!

At the first log (line 2) we are refering to the global variable x which is equal to 10 and therefore get 10 logged.

Then at line 8 we call the function a() which creates a local variable x and logs it. At line 5, inside the function a() since we create a new variable x any reference to x inside the function will be made to this new local variable which is 5, NOT to the global variable x which is 10.

The global variable x, is overidden inside the function a(), just for the time being of the function's execution. After that the local variable is deleted which means that reference shifts back to the global x. Therefore at line 10, we again get 10 logged.

Conclusion

Scoping is vital to programming since it makes sure that we as developers know when to declare variables at what locations. Sometimes we want variables to be created and deleted as soon as a function completes, whereas sometimes we want them to remain for the entire page's duration.

Scoping means that programmers know how their programs work, which is essential for them - programs shouldn't be dictating us, but we shall be dictating them. And scoping makes this possible!