📒
SDV503
  • SDV503
  • Command Prompt
    • Windows Command Prompt
    • Mac OS Terminal
  • GIT & GITHub
    • GitHub
    • Git
      • Git Workflow
        • Forking Workflow
  • README
    • How to write a readme.md file?
    • Write a better README.me
    • Generate a README for GitHub Repo Quickly
  • Code-comments
    • Clean Comments
    • Writing Comments in a Good way
  • Pair Coding
    • What is Pair Coding?
    • Pair Programming Experience
  • Programming?
    • What is Programming?
    • What Is A Programming Paradigm?
    • JavaScript Programming Paradigms
  • Number Systems
    • Decimal and Binary numbers
  • JavaSCript
    • Introduction To JavaScript
      • The JavaScript Engine
  • JS Call Stack
    • JavaScript call stack
    • JavaScript & Memory
      • Memory Leaks in JavaScript
    • Execution Context and Execution Stack in Javascript
      • Javascript Execution Context and Hoisting
  • JavaScript Variables
    • Introduction to JS Data Types
    • Primitive and Non-Primitive
    • Operator precedence and associativity
      • JS Operators Part One
      • JS Operators Part Two
      • JS Operators Part Three
    • Clean Code for JS Variables
  • JavaScript Scopes
    • Scope (Chain) Visualized
  • Javascript  — this keyword
  • JavaScript Data Types
    • More JavaScript Data Types
  • JavaScript Expressions and Statements
  • if/else, switch and ternary operator
    • If/Else statement
  • Switch Statement
  • Ternary Operator
  • JavaScript Loops
    • Loops in JavaScript
      • Trouble With Loops
  • Objects
    • JavaScript Objects
      • Prototypal Inheritance Visualized
      • JavaScript Number Object
      • JavaScript String Object
  • Functions
    • JavaScript Function Part One
    • JavaScript Function Part Two
    • Immediately Invoked Function Expressions ~ IIFE
    • JS => Arrow Functions
    • JavaScript Callback
    • Hoisting in JavaScript
      • Hoisting Visualized
    • Recursion Functions
    • Curry and Function Composition
  • JavaScript Features
    • JSpread Operator
    • JavaScript Built-in Functions & Objects
  • Data Structures&Algorithms
    • JavaScript’s Data Types
    • Data Structures in JavaScript
      • Introduction to Big O Notation
      • Big O Notation in Javascript
      • Linked Lists
        • Linked Lists — 2
      • Hash Tables
      • Stack & Queue
  • TLDR
    • Single quotes (‘ ’) and double quotes (“ ”) in JavaScript
  • ES6
    • Generators and Iterators
    • Javascript Classes
    • JavaScript closures
    • JavaScript Promises & Async/Await
      • Event Loop Visualized
  • C#
    • What does C#? (C Sharp)
    • C# vs JavaScript
    • What Is The Difference Between C#, .NET, ASP.NET, Microsoft.NET, and Visual Studio?
    • What is the .NET Framework?
    • Methods and Properties of Console Class in C#
    • Datatypes in C#
    • C# Code Comments
    • The if statement
    • The switch statement
    • Loops
    • Comparison operators
    • Addition assignment operators
    • The String Interpolation Operator
    • Arrays
    • Lists
    • Dictionaries
Powered by GitBook
On this page

Was this helpful?

  1. JavaScript Scopes

Scope (Chain) Visualized

PreviousJavaScript ScopesNextJavascript  — this keyword

Last updated 4 years ago

Was this helpful?

Let's take a look at the following code:

const name = "Lydia"
const age = 21
const city = "San Francisco"


function getPersonInfo() {
  const name = "Sarah"
  const age = 22

  return `${name} is ${age} and lives in ${city}`
}

console.log(getPersonInfo())

We're invoking the getPersonInfo function, which returns a string containing the values of the name, age and city variables: Sarah is 22 and lives in San Francisco. But, the getPersonInfo function doesn't contain a variable named city? How did it know the value of city?

First, memory space is set up for the different contexts. We have the default global context (window in a browser, global in Node), and a local context for the getPersonInfo function which has been invoked. Each context also has a scope chain.

For the getPersonInfo function, the scope chain looks something like this (don't worry, it doesn't have to make sense just yet):

Alt Text

The scope chain is basically a "chain of references" to objects that contain references to values (and other scopes) that are referenceable in that execution context. ( "Hey, these are all the values you can reference from within this context".) The scope chain gets created when the execution context is created, meaning it's created at runtime!

However, I won't talk about the activation object or the execution contexts in general in this post, let's just focus on scope! In the following examples, the key/value pairs in the execution contexts represent the references that the scope chain has to the variables.

The scope chain of the global execution context has a reference to 3 variables: name with the value Lydia, age with the value 21, and city with the value San Francisco. In the local context, we have a reference to 2 variables: name with the value Sarah, and age with the value 22.

When we try to access the variables in the getPersonInfo function, the engine first checks the local scope chain.

The local scope chain has a reference to name and age! name has the value of Sarah and age has the value of 22. But now, what happens when it tries to access city?

In order to find the value for city the engine "goes down the scope chain". This basically just means that the engine doesn't give up that easily: it works hard for you to see if it can find a value for the variable city in the outer scope that the local scope has a reference to, the global object in this case.

In the global context, we declared the variable city with the value of San Francisco, thus has a reference to the variable city. Now that we have a value for the variable, the function getPersonInfo can return the string Sarah is 22 and lives in San Francisco

We can go down the scope chain, but we can't go up the scope chain. (Okay this may be confusing because some people say up instead of down, so I'll just rephrase: You can go to outer scopes, but not to more inner... (innerer..?) scopes. I like to visualize this as a sort of waterfall:

Or even deeper:

Let's take this code as an example.

It's almost the same, however there's one big difference: we only declared city in the getPersonInfo function now, and not in the global scope. We didn't invoke the getPersonInfo function, so no local context is created either. Yet, we try to access the values of name, age and city in the global context.

It throws a ReferenceError! It couldn't find a reference to a variable called city in the global scope, and there were no outer scopes to look for, and it cannot go up the scope chain.

This way, you can use scope as a way to "protect" your variables and re-use variable names.

Besides global and local scopes, there is also a block scope. Variables declared with the let or const keyword are scoped to the nearest curly brackets ({}).

const age = 21

function checkAge() {
  if (age < 21) {
    const message = "You cannot drink!"
    return message
  } else {
    const message = "You can drink!"
    return message
  }
} 

You can visualize the scopes as:

We have a global scope, a function scope, and two block scopes. We were able to declare the variable message twice, since the variables were scoped to the curly brackets.

To quickly recap:

  • You can see "scope chain" as a chain of references to values that we can access in the current context.

  • Scopes also make it possible to re-use variable names that were defined further down the scope chain, since it can only go down the scope chain, not up.

Alt Text
Alt Text
Alt Text
Alt Text
Alt Text
Alt Text
Alt Text
Alt Text