Scope of execution context in Javascript
September 28, 2018
Every function in Javascript creates Execution Context(EC) when it is called. Lexical scope of a function’s execution context is determined where it is defined, not where it runs. Let’s see how lexical scope of a function’s EC works in javascript.
function a() {
console.log("a() called ", foo)
}
function x() {
function b() {
console.log("b() called ", foo)
}
var foo = 1
b()
a()
}
var foo = 0
a()
x()
Here, function a
’s lexical scope of EC is functions a's EC
-> global EC
.
However, functions b
’s scope of EC is b's EC
-> x's EC
-> global EC
.
Output of the code above:
a() called 0
b() called 1
a() called 0
As in the output, lexical scope of EC for calling a()
inside function x
is not a’s EC -> x’s EC -> global EC.
It is a's EC -> global EC
. So, it sees foo = 0
defined in global EC, not foo = 1
in x’s EC.
If you omit var
inside functions x
like below:
function a() {
console.log("a() called ", foo)
}
function x() {
function b() {
console.log("b() called ", foo)
}
foo = 1
b()
a()
}
var foo = 0
a()
x()
foo
is refered to one in global EC by default. So output would be:
a() called 0
b() called 1
a() called 1
This can be problematic since it causes global side-effect.
This usage is legal even if you use use strict
like this:
"use strict"
function a() {
console.log("a() called ", foo)
}
function x() {
function b() {
console.log("b() called ", foo)
}
foo = 1
b()
a()
}
var foo = 0
a()
x()
Code snippet above runs with no error. That’s because foo is defined in the top-level scope in the course of tracing the definition of foo. Developer’s care should be taken.
On the other hand, misterious behavior like this:
function a() {
console.log("a() called ", foo)
}
function x() {
function b() {
console.log("b() called ", foo)
}
foo = 1
b()
a()
}
x()
can happen with output
b() called 1
a() called 1
Does a()
called inside function x
refer foo = 1
in function x
’s execution context? No.
foo = 1
without var
inside function x
implicitly define foo in the global context. That’s how a()
got foo = 1
.
use strict
can help prevent this case by throwing error, like so:
"use strict"
function a() {
console.log("a() called ", foo)
}
function x() {
function b() {
console.log("b() called ", foo)
}
foo = 1
b()
a()
}
x()
ReferenceError: foo is not defined
Written by Sangche. Github