This post is mainly about scope in vanilla JavaScript and the different ways it can be used to our advantage. There are a lot of ways to look at the scope to try and better understand it, my brain always goes to the analogy that if your app is a car then the scope is the various compartments within the vehicle.
Global scope is the interior of your car, from there you can open your hood and trunk but you do so with a “function” because you are in the global scope. Your trunk is like a blockchain only accessible within itself (unless your rear seats fold down to give access to the trunk like naming a variable var within a block but for my example, I am not referencing a car like that or naming a variable var within my block) you can pack as much as you want into your trunk but if you want access to it inside your interior you will have to pull it out of the trunk and put it into global. Your engine compartment is like a function scope it is also self-contained but there are many systems working with each other and handing down the info to child subsystems to allow everything to work.
Global scope can be used pretty safely within the smaller apps but as your app builds in size declaring variables within a global scope can lead to lots of debugging and headaches later down the line. It is best practice if you can to declare variables within the scope of where they will be used to avoid overwriting their value or accessing the wrong variable with a function.
Back to my example from above if you think about the inside of your car while you are sitting in the driver’s seat you have access to the whole car you can reach over and open your glove box you can use your hood and trunk release and it is all within an arms reach which is really nice. You can not, however, pull something out of your engine compartment or from your trunk from the driver’s seat, but you can affect those compartments from your driver’s seat.
//example 1
const varible1= "Hello world"
function showInConsoleLog(){
console.log(varible1)
}
showInConsoleLog()
excepted return in console
console Hello World
//example 2
const firstNumber = 2
const secondNumber = 4
function addNumberTogether(){
const numbersAddedTogether = (firstNumber + secondNumber)
console.log(numbersAddedTogether)
}
addNumberTogether()
excepted return in console
console 6
//example 3
const firstNumber = 2
const secondNumber = 4
function addNumberTogether(){
const numbersAddedTogether = (firstNumber + secondNumber)
}
/*
This will not show up in console even though the function is invoked and the numbers are added together.
vvv The value of numbersAddedTogether is not declared Globally, so it cannot be seen by the console.log() which is in global scope.
*/
console.log(numbersAddedTogether)
addNumberTogether()
excepted return in console
ReferenceError: numbersAddedTogether is not defined
}
Block Scope
Block scope is useful for creating Block statements, which allows your code to use and or resolve multiple statements in places where javascript excepts only one statement. An example of that is if statements and for statements where we can name a variable to be referenced for a check, but not have access to that variable outside of that statement. Example 3 in global scope shows off block scope, as well as the example below
//example 1
function increaseNumber() {
for (let x = 0; x < 5; x++) {
console.log(x)
}
}
increaseNumber()
excepted return in console
console 0
console 1
console 2
console 3
console 4
//example 2
function increaseNumber() {
for (let x = 0; x < 5; x++) {
}
/*
This will not show up in console even though x is being increased and the code does know that,
vvv x is not defined in within scope of the console log so it can not reference it vvv
*/
console.log(x)
}
increaseNumber()
excepted return in console
ReferenceError: x is not defined
Function scope is a little bit more tricky than global and block scope. Function scope back to my analogy is like your cars engine compartment. Think of your dashboard it gives you a read-out of what is happening inside your engine compartment, this is similar to returning in a function declared in global scope. It is allowing the results of the function to be viewed from outside the function, but that doesn’t mean you have access to the sensors interior variables only its result. There is more info though from the engine compartment that you do not have access to from your dash, this is similar to a function declared within a function you can not directly see the results on your dash. Even though that info might be critical to making sure your car is working it does not need to be viewed by you (Global scope).
Now let’s talk about your gas pedal, its a function that is declared in global scope but can affect the engine. This is similar to using the argument passed into a function to use variables declared within a function scope with that global function. When the function is invoked within another scope is can access the data within that scope if it is passed the data as the argument while invoking. To put this back to the analogy when you push your gas pedal you are telling your car you want to go faster, it then takes that function and passes it to the engine. The engine will then decide by running that function with some other data as the argument if that is possible to do. So your function(gas pedal) actually has access to data that is well within another function scope(engine compartment) as long as when the function (gas pedal) is invoked within another function scope (engine compartment) it is passed the data as an argument. There are some issues with this analogy if you really break it down but hopefully, this brief overview helped someone understand scope a little better
//example 1
function getNameFromFunctionScope(name){
console.log(name)
}
function createFirstNameToRetrieve(){
const firstName = 'John'
const middleName = firstName + ' Paper'
const lastName =middleName + ' Smith'
getNameFromFunctionScope(lastName)
}
createFirstNameToRetrieve()
excepted return in console
console John Paper Smith
/*
^^^ In this example even though the console.log() is in a separate scope lastName is available to it because, ^^^
it is invoked within the scope of lastName with lastName as an argument.
That argument is referenced as a parameter in the function and then console logged
*/
//example 2
function getNameFromFunctionScope(name){
console.log(name)
}
function createFirstNameToRetrieve(){
const firstName = 'John'
const middleName = firstName + ' Paper'
const lastName =middleName + ' Smith'
getNameFromFunctionScope(middleName)
}
createFirstNameToRetrieve()
excepted return in console
console John Paper
/*
Similar to the above example. This is to show that even though the function creates a full name
we can access the variables separately, if we use that varible as the parameter when we invoke our function.
*/