Coming from magical Rails-land, where everything is abstract and intuitive (if you ask me), wrapping your head around Javascript can seem intimidating. That's why we're going to take it really slow.
Let's take a look at how scoping works in Javascript. This will function as a quick (but sturdy!) foundation for my next post on object orientation in Javascript.
What is scoping?
There are two different usages of the word "scope" when it comes to Javascript.
Lexical Scope refers to the areas in your code in which you have access to certain variables. You can think of lexical scoping as the gatekeepers of variables--the scope of a variable determines where you can access it. It's like a wristband at a music festival--but a little bit backwards. In real life, the more VIP you are, the closer to the stage you get to be. In Javascript land, variables defined inside a function can't leave that function. Variables defined outside a function can go wherever they want.
Let's take a look:
The hello
variable is set outside of the following function. We consequently consider it to have a global scope. It is the most VIP of variables. It can go wherever it wants, even backstage with Niki Minaj (or whoever else the kids are listening to these days).
Since the hello variable has a global scope, we can access it inside of our greeting
variable. Thus, the invocation of the function stored in the greeting variable will log to the console the string stored in the hello
variable:
Now let's take a look at the reverse:
Notice that the function stored in the salutation
variable is attempting to call on a variable defined inside another function. The hello
variable does not have the right wristband for that.
In Memory Scopes
In memory scopes are also known as execution contexts. These are the memory systems a program creates as it runs to store variables and their values.
Let's take a look at how a program creates a data store as it runs, using our above example. I'm going to draw and you're not allowed to make fun of me:
First, the interpreter creates a memory store for the global variables. The variable hello
, which points to a string, is stored in memory along with its value. The variable greeting
, which points to a function, is stored similarly. At this point, the code within the function that greeting
points to is not being run, because it is not yet invoked. Our program, as it executes, is simply storing the knowledge that greeting
has a value of a certain function. Let's take a look below. On the left, we see our source code. On the right, we imagine our program as it is run in real time.
Second, the program will interpret the invocation of the greeting function: greeting()
. In doing so, it will enter the scope of the function stored by the greeting
variable. This means we are entering the local scope that is opened up within the global scope. Inside the local scope, our program needs to access the value of the hello
variable. So, it looks it up in the global space, where it was stored earlier in memory:
Thus, our program outputs "Sup bro?", a classy and mature greeting, to the console.
Interestingly, if we were to invoke the function stored in the greeting
variable again, we would have created two different objects. Each object would be stored separately in memory. Even though the two objects would appear the same and output the same greeting, they are not the same object.
That's all for now! Stay tuned for more of my adventures in Javascript.