Core Concepts
Every Function Invocation = New Execution Context
This is the single most important idea in this topic. When a function is invoked (called), JavaScript creates a brand new execution context for it. This context has:
- Its own Variable Environment (memory space) — completely independent
- Its own Code Execution phase — runs the function body line by line
- Its own copy of local variables — even if they share names with global variables
When the function finishes (returns), its entire execution context is destroyed. The local variables cease to exist.
Complete Walkthrough — The Master Example
var x = 1;
a();
b();
console.log(x);
function a() {
var x = 10;
console.log(x);
}
function b() {
var x = 100;
console.log(x);
}Step-by-step Execution:
- GEC Memory Phase:
x → undefined,a → {fn},b → {fn}. GEC is pushed onto Call Stack. - GEC Execution:
x = 1(replaces undefined with 1). a()is called: A new execution context forais created and pushed onto the stack. Ina’s memory phase:x → undefined. Ina’s execution:x = 10, thenconsole.log(x)prints 10 (the local x). Context forais destroyed and popped.b()is called: New execution context forb. Inb’s memory:x → undefined. Inb’s execution:x = 100, thenconsole.log(x)prints 100. Context forbis destroyed and popped.- Back in GEC:
console.log(x)prints 1 — the global x was never touched by a() or b(). - GEC is destroyed and popped. Call Stack is empty. Program done.
Final Output: 10 → 100 → 1
Call Stack During the Example
Here’s how the Call Stack evolves:
[GEC] → [GEC, a()] → [GEC] → [GEC, b()] → [GEC] → Empty ✓
Variable Environment — The Technical Term
The Variable Environment is the memory component of an execution context. It’s where all local variables, function declarations, and function parameters are stored. Each execution context has its own independent variable environment.
When people say “a function has its own scope,” they’re really saying it has its own variable environment inside its own execution context.
What Happens to Variables When a Function Returns?
When a function finishes execution:
- Its execution context is completely destroyed
- All local variables in its variable environment are garbage collected
- The memory is freed up
- The return value (if any) is passed back to the calling context
This is why local variables are not accessible outside their function — they literally don’t exist anymore after the function returns. (The exception to this is closures, covered in Topic 10.)
Parameters Are Local Variables Too
Function parameters are treated as local variables within the function’s execution context. They are allocated in the function’s variable environment during its memory creation phase.
function greet(name, greeting) {
// name and greeting are local variables in greet's variable environment
console.log(greeting + ", " + name);
}
greet("Akshay", "Hello");
console.log(name); // ReferenceError: name is not definedWith vs Without Local Declaration — Critical Difference
var x = 1;
function change() {
var x = 999; // local x — doesn't affect global
}
change();
console.log(x); // 1 ✓ global is untouchedvar x = 1;
function change() {
x = 999; // NO var/let/const — modifies global x!
}
change();
console.log(x); // 999 — global was changed!Interview Questions & Answers
Q1. What is a Variable Environment in JavaScript?
The Variable Environment is the memory component of an execution context. It stores all the variables, function declarations, and function parameters as key-value pairs within that specific execution context. Each function invocation creates a new execution context with its own independent variable environment, ensuring variables in one function don’t interfere with variables in another — even if they share the same name.
Q2. Can two different functions have variables with the same name? Will they conflict?
No, they will not conflict. Each function invocation creates its own
execution context with its own variable environment (memory space). A
variable named x inside function a() and another x inside function
b() are completely independent variables stored in separate memory
locations. They have no knowledge of each other and don’t interact in
any way. When each function returns, its execution context is destroyed
along with its local variables.
Q3. What happens to local variables when a function finishes execution?
When a function finishes execution (either by reaching the end or
hitting a return statement), its entire execution context is
destroyed and popped off the Call Stack. All local variables in its
variable environment are deallocated and become eligible for garbage
collection. They are no longer accessible. The only thing that
survives is the return value, which is sent back to the calling context.
The key exception is closures, where inner functions retain
references to outer function variables even after the outer function
returns.
Q4. What is the difference between local scope and global scope?
Global scope: Variables declared outside any function, in the Global
Execution Context. They are accessible from anywhere in the program and
live for the entire duration of the program. With var, they are also
properties of the window object.
Local scope (Function scope): Variables declared inside a function, within that function’s execution context. They are only accessible within that function and are destroyed when the function finishes. They exist only for the lifetime of that function call.
Q5. What happens if you assign to a variable without declaring it with var/let/const?
In non-strict mode, if you assign a value to a variable without
declaring it (e.g., x = 10 without var/let/const), JavaScript
creates it as a property on the global object (window.x in
browsers). This is called an “implicit global” and is considered a
bug-prone behavior. In strict mode ("use strict"), this throws a
ReferenceError: x is not defined, which is the safer behavior.
Q6. Are function parameters part of the variable environment?
Yes. Function parameters are treated as local variables within the function’s execution context. During the memory creation phase of the function’s execution context, parameters are allocated memory and initialized with the argument values passed during the call. They exist in the function’s variable environment and are destroyed when the function returns, just like any other local variable.
Q7. If a function is called multiple times, does it use the same execution context?
No. Every single function call creates a new, fresh execution
context with its own variable environment. If you call square(2) and
then square(4), two separate execution contexts are created (and
destroyed) one after the other. They share no state. This is why each
call can have different parameter values and produce different results
independently.
Q8. Explain the concept of “scope isolation” in JavaScript functions.
Scope isolation means each function creates its own enclosed environment where its variables are private and inaccessible from outside. This is achieved through the execution context model — each function call gets its own variable environment. Variables declared inside a function cannot be read or modified from outside. The global execution context cannot access local variables of a function, though a function CAN access global variables (via the scope chain). This one-way access pattern is fundamental to JavaScript’s scoping.
Q9. What is the arguments object in a function?
The arguments object is an array-like object available inside
every non-arrow function. It contains all the arguments passed to the
function, regardless of how many parameters were defined. It’s part of
the function’s variable environment. Key points:
- It has a
lengthproperty and can be accessed by index (arguments[0], etc.) - It is NOT a real array — it doesn’t have methods like
map,forEachetc. - Arrow functions do NOT have their own
argumentsobject — they inherit from the enclosing function.
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4)); // 10Q10. What is the difference between pass by value and pass by reference in JavaScript?
Primitives (number, string, boolean, null, undefined, symbol, bigint) are passed by value. The function receives a copy. Modifying the parameter inside the function does NOT affect the original variable.
Objects (arrays, objects, functions) are passed by reference (technically, a copy of the reference). The function receives a reference to the same object in memory. Modifying properties of the object inside the function DOES affect the original. However, reassigning the parameter to a new object does NOT affect the original reference.
let num = 10;
let obj = { a: 1 };
function modify(x, o) {
x = 99; // won't affect num (copy of value)
o.a = 99; // WILL affect obj (same reference)
o = { a: 0 }; // won't affect obj (reassigns local ref)
}
modify(num, obj);
console.log(num); // 10 (unchanged)
console.log(obj.a); // 99 (property was modified)Input/Output Interview Questions
I/O 1. What will be the output?
var x = 1;
a();
b();
console.log(x);
function a() {
var x = 10;
console.log(x);
}
function b() {
var x = 100;
console.log(x);
}Output: 10 → 100 → 1
Three separate x variables in three separate execution contexts. Each
function logs its own local x. The global x = 1 is never modified.
I/O 2. What will be the output? (No var inside function)
var x = 1;
function a() {
x = 10; // NO var — modifies global x
console.log(x);
}
a();
console.log(x);Output: 10 → 10
Without var/let/const, x = 10 modifies the global x. Both
logs print 10.
I/O 3. What will be the output?
var x = 10;
function a() {
console.log(x);
}
function b() {
var x = 20;
a();
}
b();Output: 10
Very important! Even though a() is called from inside b(),
function a is lexically defined in the global scope. So a’s
scope chain goes to the global scope, not to b’s scope. It finds
the global x = 10, not b’s x = 20. JavaScript uses lexical
(static) scoping, not dynamic scoping.
I/O 4. What will be the output?
var count = 0;
function increment() {
count++;
console.log(count);
}
increment();
increment();
increment();Output: 1 → 2 → 3
No local count is declared inside increment(), so it accesses and
modifies the global count. Each call creates a new execution
context, but all three access the same global variable. The state
persists between calls because it lives in the global scope.
I/O 5. What will be the output?
function a() {
var x = 10;
console.log(x);
}
function b() {
console.log(x);
}
a();
b();Output: 10 → ReferenceError: x is not defined
a() logs its local x = 10 fine. b() tries to access x but has no
local x and there’s no global x either. a’s local x was
destroyed when a() finished. b cannot access a’s variables — they
are in separate execution contexts.
I/O 6. What will be the output? (Pass by value vs reference)
var a = 5;
var obj = { val: 5 };
function change(num, o) {
num = num * 10;
o.val = o.val * 10;
}
change(a, obj);
console.log(a); // ?
console.log(obj.val); // ?Output: 5 → 50
a is a primitive — passed by value. Modifying num doesn’t affect
a. obj is an object — passed by reference. Modifying o.val changes
the actual object’s property.
I/O 7. What will be the output? (Tricky — hoisting + variable environment)
var x = 21;
var fun = function() {
console.log(x);
var x = 20;
console.log(x);
};
fun();Output: undefined → 20
Inside fun(), var x = 20 causes x to be hoisted within the
function’s scope as undefined. The first console.log(x) finds this
local x (which is undefined), NOT the global x = 21. The local
declaration shadows the global one entirely. After x = 20 runs,
the second log prints 20.
I/O 8. What will be the output? (Nested function calls)
var x = 1;
function outer() {
var x = 2;
function inner() {
var x = 3;
console.log("inner:", x);
}
inner();
console.log("outer:", x);
}
outer();
console.log("global:", x);Output: "inner: 3" → "outer: 2" → "global: 1"
Three completely separate x variables: global (1), outer (2),
inner (3). Each function logs its own local x. None affect each
other.
I/O 9. What will be the output? (Strict mode)
"use strict";
function test() {
y = 20;
}
test();
console.log(y);Error: ReferenceError: y is not defined
In strict mode, assigning to an undeclared variable is not allowed.
Without "use strict", this would silently create a global variable
y = 20. Strict mode prevents this dangerous behavior.
I/O 10. What will be the output? (Tricky — same function called twice)
function counter() {
var count = 0;
count++;
console.log(count);
}
counter();
counter();
counter();Output: 1 → 1 → 1
Each call to counter() creates a new execution context with a
fresh count = 0. The variable doesn’t persist between calls because
it’s local and gets destroyed after each return. This is why closures
are needed to maintain state (Topic 10).
I/O 11. What will be the output? (Advanced — arguments object)
function test(a, b, c) {
console.log(arguments.length);
console.log(a, b, c);
}
test(1, 2);Output: 2 → 1 2 undefined
arguments.length is 2 (number of arguments passed, not parameters
declared). c was not passed any argument, so it defaults to
undefined in the function’s variable environment.
I/O 12. What will be the output? (Tricky — reassigning parameter)
var arr = [1, 2, 3];
function addItem(list) {
list.push(4); // modifies original array
list = [99]; // reassigns local reference only
list.push(100); // pushes to the NEW local array
}
addItem(arr);
console.log(arr);Output: [1, 2, 3, 4]
list.push(4) modifies the original arr because list points to the
same array. But list = [99] reassigns the local parameter to a new
array — it doesn’t change what arr points to. list.push(100) only
affects the local [99] array, which is destroyed when the function
returns.
Quick Revision — Cheat Sheet
Remember These Points
- Every function call → new execution context → new variable environment
- Same-named variables in different functions → completely independent
- Local variables are destroyed when the function returns
var xinside function → creates localx, does NOT touch globalx- No
var/let/const→ modifies global (dangerous!) or throws error in strict mode - Parameters = local variables allocated in function’s variable environment
- Calling same function N times = N separate execution contexts (no shared state)
- Primitives → passed by value (copy), Objects → passed by reference
- Modifying object properties inside function → affects original
- Reassigning object parameter → only changes local reference
argumentsobject available in regular functions (not arrow functions)- Lexical scoping: function’s scope chain is based on where it’s defined, not where it’s called
- Local
varshadows global even before assignment line (hoisting within function) "use strict"prevents accidental global variable creation
Comments
Comments are disabled in this environment. Set
PUBLIC_GISCUS_REPO,PUBLIC_GISCUS_REPO_ID, andPUBLIC_GISCUS_CATEGORY_IDto enable.