Scope Intro
As you begin to learn about JavaScript, scope is an important concept to grasp. Scope can be defined as the section of code in which you have access to a variable. By access, it means you can reference that variable that has been stored in memory. Understanding scope will help you keep track of your variables and the values to which they are assigned. We'll go over two main types of scope: Global and Local.
Global Scope
The global scope is the area outside of all the functions in your Javascript file. A variable that is declared in the global scope means that it has been declared outside of any functions. This variable will be accessible to and can be referenced by any other scope in the file.
Local Scope
When a function is declared, it creates a local scope.
When you declare a variable inside a function, that variable is inside of that function's local scope. Each function has its own local scope. This means that the variable can only be referenced within that function. The variable will also be accessible to any code that also resides inside of that function's code block.
Scope Chain and Nested Functions
A function nested inside of a function will have access to the outer function’s variables. This is the concept of scope chain. An inner function knows about the variables in its outer scope and thus can reference those variables, but the outer scope does not have access to the variables declared in the inner function's scope. An inner function can reassign the value of a globally scoped variable, but only in the context of its own local scope. Global scope is the outermost scope in our smash.js file, so that is why the inner functions all have access to global variables.
Using let and const
With the advent of ECMAScript 6, let
and const
were introduced as the preferred ways to declare variables. Prior to ES6, var
was the only way to declare variables. Use let
to declare a variable when you intend the value assigned to the variable to change. Use const
to declare a variable when you don't intend for the value assigned to the variable to change within a scope.
In order to avoid issues with hoisting and unintentional variable assignments, it's best to use let
and const
.
Now that we've gone over the basics, we'll use the Nintendo Super Smash games in an example.
In our file's global scope, we have declared and assigned variables to the values of individual characters in the original Smash game.
The reason these characters(variables) are in the global scope is because these characters are in all of the subsequent Smash games, meaning those games need access to those characters in order for them to be part of that game's roster. Let's look at the next game Smash Melee which introduces new characters and includes the characters in the global scope.
The function smashMelee has access to all of the global variables in the smash.js file, but all of the characters(variables) inside of the smashMelee cannot be accessed in the global scope. The variables inside of smashMelee can only be accessed in the function's local scope.
We're going to include the next game, smashBrawl as a function nested within the function smashMelee. What we expect here is for smashBrawl to be able to access all of the variables in the global scope, all of the variables in smashMelee's local scope, and of course smashBrawl's own local scope since it is a function.
You can see that some characters from smashMelee did not make it into the smashBrawl game, but since smashMelee is the outer function of smashBrawl, smashBrawl can access the characters(variables) of fighters who aren't actually in the game. In order to rectify this, we can reassign the values of those characters(variables) within the scope of the smashBrawl function. You'll notice that a character like Pichu who was in smashMelee but not in smashBrawl has been reassigned:
const pichu = "Pichu is not in smashBrawl"
It's important to mention that the variable of pichu has only been reassigned in the smashBrawl scope, but when you're in smashMelee's scope, the initial value assignment remains.
Here's the complete list of the games and their corresponding rosters:
//Global Scope
//Super Smash Bros 64 (smashOriginal)
const mario = "Mario never changes"
const link = "Link from Ocarina of Time is in smashOriginal and smashMelee"
const donkeyKong = "Donkey Kong"
const samus = "Samus"
const yoshi = "Yoshi"
const kirby = "Kirby"
const fox = "Fox"
const pikachu = "Pikachu"
const luigi = "Luigi"
const captainFalcon = "Captain Falcon"
const ness = "Ness"
const jigglypuff = "Jigglypuff"
function smashMelee(){
const drMario = "Dr. Mario"
const bowser = "Bowser"
const princessPeach = "Peach"
const ganondorf = "Ganondorf"
const falco = "Falco"
const iceClimbers = "Ice Climbers"
const zelda = "Zelda"
const sheik = "Sheik"
const youngLink = "Young Link"
const pichu = "Pichu"
const mewtwo = "Mewtwo"
const mrGameAndWatch = "Mr Game and Watch"
const marth = "Marth"
const roy = "Roy"
console.log(link)
return function smashBrawl(){
const diddyKong = "Diddy Kong"
const pit = "Pit"
const metaKnight = "Meta Knight"
const pokemonTrainer = "Pokemon Trainer"
const ike = "Ike"
const snake = "Snake"
const sonic = "Sonic"
const kingDedede = "King Dedede"
const wolf = "Wolf"
const lucario = "Lucario"
const wario = "Wario"
const toonLink = "Toon Link"
const rob = "ROB"
const olimar = "Olimar"
const lucas = "Lucas"
const zeroSuitSamus = "Zero Suit Samus"
const mewtwo = "Mewtwo is not in smashBrawl"
const roy = "Roy is not in smashBrawl"
const pichu = "Pichu is not in smashBrawl"
const drMario = "Dr. Mario is not in smashBrawl"
const youngLink = "Young Link is not in smashBrawl"
const link = "Currently in smashBrawl function scope- Link from Twilight Princess is in smashBrawl"
console.log(link)
return function smashWiiU(){
const palutena = "Palutena"
const duckHunt = "Duck Hunt"
const rosalinaAndLuma = "Rosalina and Luma"
const greninja = "Greninja"
const robin = "Robin"
const pacMan = "Pac-Man"
const shulk = "Shulk"
const mewtwo = "Mewtwo"
const bowserJr = "Bowser Jr"
const villager = "Villager"
const megaMan = "Megaman"
const wiiFitTrainer = "Wii Fit Trainer"
const littleMac = "Little Mac"
const darkPit = "Dark Pit"
const lucina = "Lucina"
const drMario = "Dr. Mario"
const roy = "Roy"
const ryu = "Ryu"
const cloud = "Cloud"
const corrin = "Corrin"
const bayonetta = "Bayonetta"
const miiBrawler = "Mii Brawler"
const miiSwordFighter = "Mii Swordfighter"
const miiGunner = "Mii Gunner"
const charizard = "Charizard"
const pokemonTrainer = "Pokemon Trainer is not in smashWiiU"
const iceClimbers = "Ice Climbers are not in smashWiiU"
const wolf = "Wolf is not in smashWiiU"
const link = "Currently in smashWiiU function scope- Link from Skyward Sword is in smashWiiU"
console.log(link)
return function smashUltimate(){
const darkSamus = "Dark Samus"
const daisy = "Daisy"
const ken = "Ken"
const inkling = "Inkling"
const ridley = "Ridley"
const simon = "Simon"
const richter = "Richter"
const kingKRool = "King K Rool"
const isabelle = "Isabelle"
const incineroar = "Incineroar"
const piranhaPlant = "Piranha Plant"
const joker = "Joker"
const hero = "Hero"
const banjoKazooie = "Banjo & Kazooie"
const terry = "Terry"
const byleth = "Byleth"
const iceClimbers = "Ice Climbers"
const wolf = "Wolf"
const pichu = "Pichu"
const pokemonTrainer = "Pokemon Trainer"
const youngLink = "Young Link"
const charizard = "Charizard is not in smashUltimate as a standalone character"
const link = "Currently in smashUltimate function scope - Link from Breath of the Wild
is in smashUltimate"
console.log(link)
}}}};
As mentioned with Pichu, some characters have been reassigned or newly included in the corresponding scope of the game to which they belong.
Now we're going to use Link from the Zelda series in order to convey reassigning a value to a variable and how that functions within scope.
Link is always traveling through time, dimensions, seasons, etc, but today he’s traveling through scopes so we can grasp this concept. He’s our Hero of Scope.
Link's first appearance in the Smash games is his Ocarina of Time incarnation:
If we run the smashMelee function, we see that value of the variable link being console logged:
If we run the smashBrawl function, we see a different value of the variable link being console logged:
His variable assignment is that of his Twilight Princess incarnation:
If we run the smashWiiU function, we see yet another value of the variable link being console logged:
His variable assignment is that of his Skyward Sword incarnation(sort of):
Lastly, if we run the smashUltimate function, we see the latest value of the variable link being console logged:
His variable assignment is that of his Breath of the Wild incarnation:
As you can see, the value of the character(variable) link only changed within the scope where the value was reassigned. When you're in the scope of smashUltimate, he's Breath of the Wild Link, in the scope of smashWiiU, he's Skyward Sword Link, etc. Keep in mind that the values of link are determined by the scope in which the variable is declared.
Conclusion
Improperly utilizing scope can lead to your variables being assigned to values you didn't intend them to have, which can cause issues in your code.
General rules to consider:
- use
const
andlet
instead ofvar
- declare your variables and functions at the top of a function when possible
- use global variables sparingly
Properly utilizing the concept of scope will allow you to organize your code efficiently and ensure you only have access to variables when necessary. Otherwise you can end up with variables assigned to values you didn't intend them to have, which leads to confusion!
I hope this clarifies some things about scope. Practice the concept and soon you'll be able to do this to JavaScript.
If you have any insights or additions regarding the topic of scope, please leave a comment!
Top comments (0)