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 0As 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 1This 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 1Does 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