16. JavaScript Scope

What you will learn

  • What scope means
  • Global, function, and block scope
  • How var differs from let and const
  • What a closure is

What is scope?

Scope decides where in your code a variable can be used. A variable that exists only in one part of the program cannot be seen from other parts, which keeps programs tidy and avoids name clashes.

Global scope

A variable declared outside any function or block is global: every part of the script can see it.

Example

<p id="demo"></p>

<script>
  const site = "BeingXpert";   // global

  function showSite() {
    return "Welcome to " + site;
  }

  document.getElementById("demo").textContent = showSite();
</script>

Output (after the script runs)

Welcome to BeingXpert

Too many globals cause clashes, especially when several scripts share a page. Keep most variables local.

Function scope

A variable declared inside a function exists only inside that function.

Example

<p id="demo"></p>

<script>
  function secret() {
    const code = 1234;      // local to this function
    return "Inside: " + code;
  }

  let outside;
  try {
    outside = code;         // not visible here
  } catch (error) {
    outside = "Outside: " + error.name;
  }

  document.getElementById("demo").innerHTML = secret() + "<br>" + outside;
</script>

Output (after the script runs)

Inside: 1234
Outside: ReferenceError

A ReferenceError means the name is not available in that scope. You will learn try...catch in the Errors lesson.

Block scope

A block is anything inside curly braces, such as an if or a loop. Variables declared with let and const stay inside their block. A var ignores blocks.

Example

<p id="demo"></p>

<script>
  if (true) {
    var oldWay = "var leaks out";
    let newWay = "let stays inside";
  }

  document.getElementById("demo").innerHTML =
    "oldWay: " + oldWay + "<br>" +
    "newWay: " + typeof newWay;
</script>

Output (after the script runs)

oldWay: var leaks out
newWay: undefined

This is why modern code uses let and const. Their behaviour is easier to predict.

Keyword Scope
var Function (ignores blocks)
let Block
const Block

Inner scopes can see outer scopes

JavaScript looks for a name in the current scope, then in the scope around it, and so on outward. This chain is the scope chain. A variable with the same name in an inner scope shadows the outer one.

Example

<p id="demo"></p>

<script>
  const level = "outer";

  function test() {
    const level = "inner";   // shadows the outer one
    return level;
  }

  document.getElementById("demo").textContent = test() + " / " + level;
</script>

Output (after the script runs)

inner / outer

Closures

A function remembers the variables from the place where it was created, even after that outer function has finished. This is a closure. It lets you keep private data.

Example

<p id="demo"></p>

<script>
  function makeCounter() {
    let count = 0;               // private to the closure
    return function () {
      count++;
      return count;
    };
  }

  const counterA = makeCounter();
  const counterB = makeCounter();

  counterA();
  counterA();

  document.getElementById("demo").textContent =
    "A: " + counterA() + ", B: " + counterB();
</script>

Output (after the script runs)

A: 3, B: 1

Each counter has its own count, and nothing outside can change it directly.

Accidental globals

Assigning to a name that was never declared can create a global by accident (in sloppy mode), which is a common source of bugs. Always declare with let or const. Adding "use strict"; at the top of a script turns such mistakes into errors.

Hoisting, in short

JavaScript registers declarations before running the code. Function declarations can be called before they appear. A let or const cannot be used before its line, or you get an error. Declare variables at the top of their scope, and you will rarely notice hoisting.

Common mistakes

  • Using a variable outside the block or function where it was declared.
  • Forgetting let or const and creating an accidental global.
  • Using var in a loop and finding the variable still alive afterwards.
  • Giving an inner variable the same name as an outer one and getting confused.
  • Using too many global variables.

Exercise

Complete makeGreeter so it returns a function. The returned function takes a name and returns the greeting, a comma and a space, then the name. The page should show Hello, Sam.

Show solution
<p id="demo"></p>

<script>
  function makeGreeter(greeting) {
    return function (name) {
      return greeting + ", " + name;
    };
  }

  const hello = makeGreeter("Hello");
  document.getElementById("demo").textContent = hello("Sam");
</script>

The inner function remembers greeting, which is a closure.

Knowledge check

1. Which keywords are block scoped?

let and const.

2. What is a closure?

A function that remembers the variables from where it was created.

3. What error appears when a variable is used outside its scope?

A ReferenceError.

Summary

  • Scope controls where a variable can be used: global, function, or block.
  • Prefer let and const, and keep variables as local as possible.
  • Closures let functions keep private data.
Scroll to Top