Variable Scope: Local, Global and Enclosing Names
Keep one student’s temporary calculation local
A school report has a school name, but each total calculation needs temporary marks. Those local values should not interfere with another report’s variables just because the names happen to be similar.
Scope is the region where a name can be resolved. A local name belongs to a function or block; an outer name can be visible to code nested inside its scope.
Locate a name
Distinguish function, block and outer bindings.
Trace shadowing
Explain which same-named value a function reads.
Reduce hidden state
Prefer explicit inputs when shared mutable globals would make behavior surprising.
Resolve a name from the inside outward
Function local
The function creates its own student name and mark.
Maya; 40Outer scope
The school name is visible from the surrounding scope.
River SchoolOutside again
The outer student name was not reassigned.
Ravi
A repeated name can describe a different binding
JavaScript let and const belong to their enclosing block, including a function body. A function can read names from its surrounding lexical scope when no nearer declaration supplies that name.
A nearer declaration with the same name shadows the outer one. This does not make the two variables automatically connected. Excessive shadowing is confusing; use distinct names when it obscures meaning.
Before starting, review function inputs and results. These examples use JavaScript; other languages can use different syntax and rules.
Trace local and outer student names
Inside report, studentName resolves to Maya. The school name comes from the outer scope. After the function call, the outer studentName remains Ravi.
The local mark is not available by that name outside the function. Passing or returning a value is a clearer way to share it deliberately.
JavaScript · local teaching example
const schoolName = 'River School';
const studentName = 'Ravi';
function report() {
const studentName = 'Maya';
const mark = 40;
return schoolName + ': ' + studentName + ' ' + mark;
}
console.log(report());
console.log(studentName);Expected output
River School: Maya 40
RaviA block can also have its own value
The braces create a block scope for this let declaration. The inner count shadows the outer count while execution is inside the block.
Leaving the block restores access to the outer binding. It does not assign the inner value back to it.
JavaScript · local teaching example
let count = 10;
{
let count = 2;
console.log(count);
}
console.log(count);Expected output
2
10Apply the rule to a small change
Rewrite the report so the student name is supplied as a parameter. Call it for Maya and Asha.
Worked answer
The caller supplies the changing student name explicitly. The function can still read the fixed school name, but its student-specific behavior no longer depends on an outer student binding.
JavaScript · local teaching example
const schoolName = 'River School';
function report(studentName) {
return schoolName + ': ' + studentName;
}
console.log(report('Maya'));
console.log(report('Asha'));Expected output
River School: Maya
River School: AshaRecognize mistakes and limits
Assigning to an existing outer JavaScript let without a nearer declaration changes that shared binding. Such hidden changes make call ordering matter. Prefer explicit inputs and results unless shared state is a deliberate design.
Python has global and nonlocal declarations for assignments: global targets a module-level binding, while nonlocal targets an existing enclosing function binding. They are Python syntax, not JavaScript keywords. Reading an outer name and assigning one have different scope implications.
JavaScript var has function-scoped behavior unlike let’s block scope. Reads before a let or const declaration is reached can throw. Do not try to infer those rules only from indentation.
For the language or tool rules used here, see JavaScript functions and scope.
Check the core idea
JavaScript · code for this question
const schoolName = 'River School';
const studentName = 'Ravi';
function report() {
const studentName = 'Maya';
const mark = 40;
return schoolName + ': ' + studentName + ' ' + mark;
}
console.log(report());
console.log(studentName);Apply the idea to a new situation
Know which binding each read and write uses
Scope controls name resolution. Local and block declarations can shadow outer names; shared outer writes can create hidden dependencies. Language-specific global and nonlocal rules should be read in that language’s context.
Connect this idea with functions retaining access to outer bindings and clear names and responsibilities.
Reaching the recap and completing the quizzes are separate milestones.