Lexical scoping means variable accessibility is determined entirely by where code is written in your editor, not where it is executed at runtime (So Call stack don't decide the value).
1. Lexical Scoping in Action
Inner functions can look "out" to access parent variables, but parent functions cannot look "in".
const globalVar = "global";
function outer() {
const outerVar = "outer";
function inner() {
console.log(`${outerVar} & ${globalVar}`); // Looks outward
}
return inner;
}
const myFunc = outer();
myFunc(); // OUTPUT: "outer & global"
Lexical Scope Execution Flow
When a function executes, it pushes a frame onto the Call Stack while referencing its static birth environment to resolve variables:
=======================================
CALL STACK & LEXICAL SCOPE CHAIN
=======================================
| inner() | ---> [References outer() Birth Scope] ---> outerVar
+----------------+
| myFunc() | (Running in global context)
+----------------+
| Global Context| ---> globalVar
==================
Even though myFunc() runs later in the global space, it permanently remembers the variables from its original birthplace via the scope chain, completely independent of its active position on the call stack.
You must be thinking this is there is all languages what's so special but no my friend not everyone have it...
2. The Opposite: Dynamic Scoping
Most languages use lexical scope because it is predictable. Rare configurations (like Bash or Perl using specific keywords) use dynamic scoping, where a function looks for variables based on where it is called in the stack, ignoring where it was written.
# --- Dynamic Scope Example (Perl) ---
$x = "global";
sub print_x { print "$x\n"; }
sub caller_func {
local $x = "dynamic";
print_x(); # Called from here
}
caller_func(); // OUTPUT: "dynamic" (JavaScript would output "global")
Dynamic Scope Call Stack Representation
In this model, the engine looks directly down the active execution stack to resolve values:
============================
CALL STACK (Dynamic Lookup)
============================
| print_x() | <-- Looks down directly to caller_func for \$x
+----------------+
| caller_func() | <-- Declares local \$x = "dynamic"
+----------------+
| Global Context|
==================
Because Perl uses dynamic scoping here, print_x() checks the execution call stack frame immediately below it, sees it was called by caller_func, and steals its local $x.
Summary
- Lexical Scope: Where the variable was written matters. Uses a static scope chain.
- Dynamic Scope: Where the function was called matters. Reads directly from the runtime Call Stack.
Top comments (0)