DEV Community

mikkel250
mikkel250

Posted on

Scope in JavaScript

IIFE pattern

If you want to use a variable that exists in a larger, enclosing scope (e.g. global), or "hide" it to avoid accidental use/reassignment, or want to avoid polluting the global namespace, an Immediately Invoked Function Expression (IIFE) can be used. It will not reassign the variable in the parent scope, because it first looks for the name in the local scope and uses it if found.

var name = "Mikkel";

(function changeName() {
  var name = "Bob";  // declares new variable in the function scope
  console.log(name); // "Bob" is logged in the console
})();  

console.log(name);   // "Mikkel"

Wrapping the entire function in the parentheses has the effect of turning it into an expression instead of a function declaration. This allows the function to be immediately used and then discarded, and accomplishes the tasks of using the same variable name that exists in enclosing scope without affecting it.

Block scoping

Another method for accomplishing the same goal is to use block scoping, using the keyword "let", which will allow for a more concise method. Interestingly, blocks are not scopes until the have let or const used inside of them, but once they have been, it creates a local scope.

var name = "Mikkel";

// wrapping the statement in curly braces and using 'let' creates local scope
{
    let name = "Bob";
    console.log(name);   // "Bob" is logged in the console
}

console.log(name);   // "Mikkel"

var and let

A different mental model for when to use var vs let would be to use var when you need access to the variable outside of the local scope. For example, in a try/catch block, because var is available in the enclosing scope (in the example below, the function scope), it avoids having to create an undefined variable at the top of the function scope just so it can be used in the block below.

function lookupRecord(searchStr) {
  try {
    var id = getRecord(searchStr);
  } catch (err) {
    var id = -1;
  }

  return id;
}

Using var gives the return statement access to the id variable even though it's enclosed in the try/catch block's scope. Another advantage to using var is that it can be declared more than once in the same scope, and let cannot. It might also be handy in a long if/else block where there are lots of conditions to check, or a switch statement with lots of possible options, or where a number of different variables need to be assigned and then returned at the end of the statement.
A use of let's block scoping that can be taken advantage of is to use curly braces when variables only need to be used for a few lines of code.

function formatStr(str) {
  { let prefix, theRest;
    prefix = str.slice(0, 3);
    theRest = str.slice(3);
    str = prefix.toUpperCase() + rest;
  }

  return str;
}

const

The const keyword can be helpful as an indicator that you don't want the value to be changed, and pair it with primitive types that can't be changed anyway, because it also has some quirks. A good example would be to use it at the top of the program to store an string for an API that probably never needs to be changed by the program.

const databaseApi = "https://myDB.com/1235";

A generally good practice when using either let or const is to always declare them at the top of the scope in which they will be used, to avoid TDZ errors, because they behave differently than var when it comes to scope.

These are my notes from @getify 's Deep JavaScript Foundations v3 course on Frontend Masters. If you'd like to dive more deeply into these topics, I highly recommend the course, and you can read his 'You Don't Know JS' books on Scope and Closure, This and Prototypes, and Types and Grammar, available on Github or for purchase at your favorite bookseller.

Top comments (0)