DEV Community

loading...

Scope - JavaScript Concepts

Agney Menon
Software Developer at BigBinary. Engineer 👨‍💻 Sleeping if not Online 🤖
Originally published at blog.agney.dev ・4 min read

This is part of a series where I try to explain through each of 33 JS Concepts.

Originally written on my blog with interactive examples

This part corresponds to the Scope.

Scope

What is scope of a variable?

Scope in programming stands for visibility and usage. For reasons considered obvious (but ones that we will still discuss), we cannot allow all variables in our program to be global. Scope is what limits the variable to used across certain limits and boundaries.

Why scope variables?

1. Collision Avoidance

We cannot declare two variables with the same name. This would throw a reference error.

var length = 1;
// some operation going on, after sometime you think
var length = 1; // Nope!`}

But we absolutely cannot not use the same variables for different purposes. If there are no boundaries, it becomes confusing for people who read your code. This becomes more problematic when there are lots of people on the team. How does anyone know if someone else has already declared the variable?

Clear boundaries on where you can access a variable makes it easier for all developers in the project to avoid conflcits.

2. Garbage Collection

When we complete the usage of a variable, we want the variable and the data it is holding to be garbage collected. In dynamic languages, we expect this to happen automatically. But if we don't have any boundaries on where the variable can be accessed it would happen that the compiler does not have any hint on when to collect the garbage. Except may be at the end.

Having clear boundaries on where variables can be accessed can tell the compiler, that at the end of this scope it is safe to garbage collect these variables.

3. Ownership

If all our variables are global, it means that anyone can change them.

For eg. in one of the maintanence projects I had to make a Custom Event to broadcast an event to another part of the application itself. But whatever I did, I could not get the custom event to fire. What happened was that someone else had already declared a class named CustomEvent (they wanted to customise the Event class, so be it!) on the global window and it was overriding my interpretation. Except the other person (git blame) who did it, did not even know that a function named CustomEvent actually existed in JavaScript.

Imagine this happening to your variables, randomly at runtime. This is what happens if we do have some sort off ownership for the variables and functions that we write.

JavaScript has two kinds of scope:

  1. Block Scope
  2. Function Scope

We will talk about function scope first.

Function Scope

Function Scope means that any variable declared would be available inside the function. This has existed and was widely used from olden times in JavaScript.

function action() {
  var a = 2;
  ... // actions
  // a can be accessed anywhere in this function.
}

Hoisting

Wherever you declare a variable, JavaScript would proceed to hoist these upto the top of their scope. But let us be semantically correct here. JavaScript does not move the variables physically all your code remains the same. The compiler just picks the variables in it's current scope and declares them in compiler time with the value undefined.

function init() {
  console.log(a);
  var a = 1;
}

init();

This is how you can access a variable before declaration and get undefined as an answer.

You don't have to be afraid of hoisting. In fact hositing is what helps you when declaring functions in whichever order you want. Since the compiler would hoist it to the top anyway, it does not matter which order you declare it in. But with variables declared with var, it is important to write short precise functions.

Also, note that only declarations are hoisted, they would not take any value if used before initialisation.

Block Scope

This is widely used from ES6. Block refers to a {} in a program.

Block Scope means that the variables defined inside a {} can only be used inside it. Variables can be put in block scope by declaring them with let or const.

Note that functions also form block scope.

function action(limit) {
  const a = 10; // a can only be used inside this function
  if (a < limit) {
    const b = a + 2; // b can only be used inside this if block, a can also be used here as this block is inside the execution context of a's block
    return b;
  }
}

Hoisting

Does hoisting happen in Block Scope? Yes. But if we try and use a variable before it's actual declaration, we get a ReferenceError.

That does not make any sense. If they are hoisted, shouldn't they be undefined?

To get ahead of this question, JavaScript spec defines something known as a Temperal Dead Zone (TDZ). This is the difference of when it is memory (remember: Hoisting is just compiler putting variable declarations in memory) and it's actual declaration in code. When a block scoped variable in TDZ is accessed, it throws a ReferenceError.

Does this change the way I write code?

Well, it should. Scopes and Closures are some of the most integral cornerstones of the language. It can and should influence the way you think about the language and declarations.

Is there something I missed? Something wrong? Something good? Ping me on Twitter

Discussion (0)