Look Up Names Where Code Was Defined
Look Up Names Where Code Was Defined
Lexical scope resolves an outer name using the place where a function was defined. Calling the function from a different scope does not replace its definition's surrounding bindings.
Before this topic, review Find Where a Name Is Visible if its terms are unfamiliar.
What you’ll learn
- Explain look up names where code was defined through the school example.
- Trace the shown operations and distinguish their result from displayed output.
- Make the practice change and explain its consequence: The function uses the outer threshold 75; the call-site threshold 80 is still irrelevant.
Work through the school example
This is JavaScript using language features and the host console. Read the initial values, then follow each operation to its displayed result. A declaration names a value, a function call performs an operation, and console.log displays its arguments.
JavaScript · school.js · complete example
const passMark = 50;
function passed(mark) { return mark >= passMark; }
{ const passMark = 80; console.log(passed(72)); }
Expected output
trueRun in JavaScript compiler →What is Lexical Scope in JavaScript?
In JavaScript, lexical scope (also called static scope) means that the accessibility of variables is determined by the position of functions and blocks in the source code — not at runtime, but when the code is written. In simpler terms, inner functions have access to variables defined in their outer (parent) scopes.
Understanding Lexical Scope with a Basic Example
function outerFunction() {
let outerVariable = "I'm from the outer function";
function innerFunction() {
console.log(outerVariable);
}
innerFunction();
}
outerFunction();
I'm from the outer function
Explanation:
Here, innerFunction is defined inside outerFunction, so it has access to outerVariable due to lexical scoping. JavaScript knows this during the time of writing the code, not at runtime.
Scope Chain: How JavaScript Finds Variables
When a variable is accessed, JavaScript looks for it in the current scope. If it's not found, it walks up the scope chain — all the way to the global scope if necessary.
let globalVar = "Global";
function levelOne() {
let levelOneVar = "Level 1";
function levelTwo() {
let levelTwoVar = "Level 2";
console.log(globalVar); // Accessible
console.log(levelOneVar); // Accessible
console.log(levelTwoVar); // Accessible
}
levelTwo();
}
levelOne();
Global
Level 1
Level 2
But It Doesn’t Work in Reverse
function outer() {
let outerVar = "outer";
function inner() {
let innerVar = "inner";
console.log(outerVar); // Works
}
inner();
console.log(innerVar); // ❌ Error: innerVar is not defined
}
outer();
outer
Uncaught ReferenceError: innerVar is not defined
Variables Are Not Shared Across Siblings
Lexical scope only applies to nested relationships, not sibling functions.
function one() {
let msg = "from one";
}
function two() {
console.log(msg); // ❌ Error
}
one();
two();
Uncaught ReferenceError: msg is not defined
Nested Functions and Lexical Environment
Each function creates its own lexical environment. Inner functions carry a reference to their parent's scope. Let's visualize that:
function grandParent() {
let gp = "grandparent";
function parent() {
let p = "parent";
function child() {
console.log(gp); // ✅
console.log(p); // ✅
}
child();
}
parent();
}
grandParent();
grandparent
parent
Real-Life Scenario: User Authentication Flow
function authenticate(username) {
let secret = "token_" + username;
function getToken() {
return secret;
}
return getToken;
}
const tokenFetcher = authenticate("JohnDoe");
console.log(tokenFetcher()); // Lexical scope retains 'secret'
token_JohnDoe
Closures Are a Direct Result of Lexical Scope
A closure happens when a function "remembers" its lexical scope even after the outer function has finished executing.
function counter() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
const increment = counter();
increment(); // 1
increment(); // 2
increment(); // 3
1
2
3
Why Lexical Scope Matters
- Helps with code modularity and predictability.
- Provides the foundation for closures and callback functions.
- Improves memory efficiency when managing state in functions.
Common Mistakes to Avoid
- Thinking variables are dynamically scoped (they’re not).
- Expecting sibling functions to access each other’s scope.
- Misunderstanding how closures keep references, not copies, of variables.
Conclusion
Lexical scope is a core concept that gives JavaScript its power and flexibility. Mastering it lays the foundation for understanding closures, module patterns, and advanced concepts like currying and memoization. Always remember — where you write your functions matters just as much as how you write them.
Recognize the important boundary
The call-site block is not the function's lexical parent. A closure can still observe later changes to a captured mutable binding.
Try a small variation
JavaScript · original source for practice
const passMark = 50;
function passed(mark) { return mark >= passMark; }
{ const passMark = 80; console.log(passed(72)); }
Your task: Replace passMark = 50 with passMark = 75. Predict the result before running the edited program.
The source is repeated here. If the edit targets the HTML rather than the script, use the markup repeated below; the worked answer also repeats the changed markup.
Worked answer and reasoning
The function uses the outer threshold 75; the call-site threshold 80 is still irrelevant.
JavaScript · complete worked variation
const passMark = 75;
function passed(mark) { return mark >= passMark; }
{ const passMark = 80; console.log(passed(72)); }
Expected output
falseRun in JavaScript compiler →Predict the original program
JavaScript · original program for this question
const passMark = 50;
function passed(mark) { return mark >= passMark; }
{ const passMark = 80; console.log(passed(72)); }
Keep the useful idea
Lexical scope resolves an outer name using the place where a function was defined. Calling the function from a different scope does not replace its definition's surrounding bindings.
Check your variation against this explanation: The function uses the outer threshold 75; the call-site threshold 80 is still irrelevant.
Use the JavaScript array reference library for individual array operations and boundary tests to check a rule independently.
Reaching the recap and completing the quizzes are separate milestones.