DEV Community

Steven Frasica
Steven Frasica

Posted on

Scope and JavaScript Variables

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.

Alt Text

In our file's global scope, we have declared and assigned variables to the values of individual characters in the original Smash game.

Alt Text

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.

Alt Text

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.

Alt Text

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:

Alt Text

If we run the smashMelee function, we see that value of the variable link being console logged:

Alt Text

If we run the smashBrawl function, we see a different value of the variable link being console logged:

Alt Text

His variable assignment is that of his Twilight Princess incarnation:

Alt Text

If we run the smashWiiU function, we see yet another value of the variable link being console logged:

Alt Text

His variable assignment is that of his Skyward Sword incarnation(sort of):

Alt Text

Lastly, if we run the smashUltimate function, we see the latest value of the variable link being console logged:

Alt Text

His variable assignment is that of his Breath of the Wild incarnation:

Alt Text

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 and let instead of var
  • 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.

Alt Text

If you have any insights or additions regarding the topic of scope, please leave a comment!

Discussion (0)