Reputation: 1
I've been attempting to solidify my understanding of JS's execution contexts, and am having trouble getting an explanation as to why the code below does not print out "hello world".
var foo = "foo";
function test1() {
console.log(foo)
var bar = "hello world";
test2();
}
function test2() {
console.log(bar);
}
test1();
It is my (admittedly very shaky) understanding that test2()
, being executed inside of test1()
, has access to test1()
's execution context and should be able to resolve the variable name bar
by moving up the scope chain into test1()
's execution context where bar
is defined. Instead, I get a reference error when attempting to print bar
.
I can understand how the code below works due to JS's lexical scoping, but I would appreciate an explanation how JS interprets each differently in terms of execution contexts and scope-chains.
function test1() {
console.log(foo)
var bar = "hello world";
function test2() {
console.log(bar);
}
test2();
}
test1();
So far, my best attempt at finding an explanation myself was by modifying the first code block like so:
var foo = "foo";
var bar = "not hello world :("
function test1() {
console.log(foo)
var bar = "hello world";
test2();
}
function test2() {
console.log(bar);
}
test1();
Here, the call to test2()
prints out "not hello world :(" defined in the global scope. My first thought was that test2()
was going up the scope chain to test1
's execution context, to the global execution context, but that doesn't seem right, as it would have found a definition for bar
inside of test1()
before reaching the global definition. Thus, my second guess is that the definition of test2()
is creating a "closure"-like capture of the global execution context when it was defined, and calling it within test1()
produces a value for bar
of null/undefined since that was its value at function definition (having no declaration at all to be hoisted). Thus, it does not move up into test1()
's execution context to search for the identifier.
Any explanations/resources would be tremendously helpful. I am obviously very new to the language, so apologies if my vocabulary/terminology isn't quite correct. Thanks in advance for your help.
Upvotes: 0
Views: 355
Reputation: 187034
Where it's called from and the scope of the caller doesn't matter. What matters for resolving local variables is where it's declared.
test2()
cannot access bar
because there is no variable named bar
in that scope when the function is declared. There is no way to manipulate that local scope after the fact. It's set in stone.
This means that a function can access a variable in the local scope, or in any scope that contains the declaration of that function. That means following the pairs of braces {}
that contain the declaration of that function all the way back to the root of the file. Think of it like a tree: your function will have access to any variable between that function and the root of the tree. It will not have access to other branches of that tree.
And this is a really good thing. It enforces good encapsulation. You want your functions to be a black boxes from the perspective of the caller. You want local variables in your function to be truly local. And you want to know what variables a function has access to when you are writing the function, rather than being surprised by what values pop in when you run the function.
Upvotes: 1