The function’s scope includes the variable x, so that variable is only known within that function. Trying to access it out in the global scope will throw an error because x is not a declared variable (it’s not even undefined).
If we move that
var declaration outside the function, it’ll be in the global scope, everyone knows about it, and we can access it within and outside of the function:
With the advent of ECMAScript2015 (aka “ES6”), two new ways to declare variables were introduced:
const, which are significant because they enable more granular control over the scope in which a variable is available.
const define local variables which are available only in the level in which they’re defined (whether a code block or function, and any contained sub-blocks).
In the following example, x is declared with
var, and that same variable called x is known throughout the function (even on lines which precede it!) and in sub-blocks. If x is declared with the newer
const, then outer scopes don’t have access to it, and if we “
let x;” again in a sub-block, it’s effectively a different variable (like how human twins separated at birth, but given the same name, are not the same person).
This is relevant because of the lexing step that happens immediately prior to executing the code, and the fact that this:
is two steps listed on one line: the declaration of the variable x, and the assignment of the integer 5 to that variable. We could also write it like this:
When the variable is declared with
var, its value is undefined, but it is known to be a variable. Then the next line makes x’s value equal to 5. But, this isn’t the case with
const. Welcome to the Temporal Dead Zone.
Within this function, the declaration of
bar is hoisted to the top of the scope, in this case, the code contained within the function
do_something(). So, effectively, it’s executed like this:
which is why trying to
undefined (we know it’s a variable, it just has no value), while
console.log(foo) throws a reference error (“a variable called ‘foo’? what are you even talking about, human?”)
This makes things like this possible:
In the first example, even though it looks like
var num is declared after we assign it, from the computer’s perspective, it noticed that we’ve declared it in the relevant scope (global), pins that to the top, and then proceeds with executing the rest of the code. In the second example, even though we invoke/call the function before we’ve defined it, that definition is hoisted to the top of the scope, so by the time we actually start executing the code, the interpreter already knows what
var variables, note that only the declaration gets hoisted, not the assignment. So, in Example 6, writing it like this:
For this reason, it’s often suggested to always declare variables at the top of the scope they’re in, so you remember the order in which the interpreter will execute your code.
const offer some protection against this behavior, since variables declared this way are not initialized with a value of ‘undefined’. So even though they’re hoisted, you’ll still get a reference error because they won’t be initialized until they’re assigned. It’s almost like they’re not being hoisted at all.
const has an added advantage of protecting against unexpected reassignment (although an object declared this way may still have its properties modified), like so:
Similarly, functions follow similar rules. Function declarations are hoisted:
… while function expressions are not:
this fits into this
A related topic, which I will discuss as it relates to scope and hoisting, is
Gordon Zhu created a nice cheatsheet which summarizes the corresponding lesson in his life-changing curriculum on Watch & Code. Essentially
this is scope dependent.
If it’s called within a regular function or just out in the wild,
this points to
If you’re in a function being called as a method,
this points to the object being acted upon (whatever’s just to the left of the dot).
An extension of this is the case where
this is used in a constructor as in Example 12, in which
this refers to the instance of the class Person:
Explicitly setting the value of
apply is outside the scope (haha!) of this blogpost.
And in a callback function, it depends on where (what scope)
this is being called in, in accordance with the previous examples.
- Hoisting - MDN Web Docs Glossary: Definitions of Web-related terms
- Scope - MDN Web Docs Glossary: Definitions of Web-related terms