16. JavaScript Scope
What you will learn
- What scope means
- Global, function, and block scope
- How
vardiffers fromletandconst - What a closure is
What is scope?
Scope decides where in your code a variable can be used. A variable that exists only in one part of the program cannot be seen from other parts, which keeps programs tidy and avoids name clashes.
Global scope
A variable declared outside any function or block is global: every part of the script can see it.
Example
<p id="demo"></p>
<script>
const site = "BeingXpert"; // global
function showSite() {
return "Welcome to " + site;
}
document.getElementById("demo").textContent = showSite();
</script>
Output (after the script runs)
Welcome to BeingXpert
Too many globals cause clashes, especially when several scripts share a page. Keep most variables local.
Function scope
A variable declared inside a function exists only inside that function.
Example
<p id="demo"></p>
<script>
function secret() {
const code = 1234; // local to this function
return "Inside: " + code;
}
let outside;
try {
outside = code; // not visible here
} catch (error) {
outside = "Outside: " + error.name;
}
document.getElementById("demo").innerHTML = secret() + "<br>" + outside;
</script>
Output (after the script runs)
Inside: 1234
Outside: ReferenceError
A ReferenceError means the name is not available in that scope. You will learn try...catch in the Errors lesson.
Block scope
A block is anything inside curly braces, such as an if or a loop. Variables declared with let and const stay inside their block. A var ignores blocks.
Example
<p id="demo"></p>
<script>
if (true) {
var oldWay = "var leaks out";
let newWay = "let stays inside";
}
document.getElementById("demo").innerHTML =
"oldWay: " + oldWay + "<br>" +
"newWay: " + typeof newWay;
</script>
Output (after the script runs)
oldWay: var leaks out
newWay: undefined
This is why modern code uses let and const. Their behaviour is easier to predict.
| Keyword | Scope |
|---|---|
var |
Function (ignores blocks) |
let |
Block |
const |
Block |
Inner scopes can see outer scopes
JavaScript looks for a name in the current scope, then in the scope around it, and so on outward. This chain is the scope chain. A variable with the same name in an inner scope shadows the outer one.
Example
<p id="demo"></p>
<script>
const level = "outer";
function test() {
const level = "inner"; // shadows the outer one
return level;
}
document.getElementById("demo").textContent = test() + " / " + level;
</script>
Output (after the script runs)
inner / outer
Closures
A function remembers the variables from the place where it was created, even after that outer function has finished. This is a closure. It lets you keep private data.
Example
<p id="demo"></p>
<script>
function makeCounter() {
let count = 0; // private to the closure
return function () {
count++;
return count;
};
}
const counterA = makeCounter();
const counterB = makeCounter();
counterA();
counterA();
document.getElementById("demo").textContent =
"A: " + counterA() + ", B: " + counterB();
</script>
Output (after the script runs)
A: 3, B: 1
Each counter has its own count, and nothing outside can change it directly.
Accidental globals
Assigning to a name that was never declared can create a global by accident (in sloppy mode), which is a common source of bugs. Always declare with let or const. Adding "use strict"; at the top of a script turns such mistakes into errors.
Hoisting, in short
JavaScript registers declarations before running the code. Function declarations can be called before they appear. A let or const cannot be used before its line, or you get an error. Declare variables at the top of their scope, and you will rarely notice hoisting.
Common mistakes
- Using a variable outside the block or function where it was declared.
- Forgetting
letorconstand creating an accidental global. - Using
varin a loop and finding the variable still alive afterwards. - Giving an inner variable the same name as an outer one and getting confused.
- Using too many global variables.
Exercise
Complete makeGreeter so it returns a function. The returned function takes a name and returns the greeting, a comma and a space, then the name. The page should show Hello, Sam.
Show solution
<p id="demo"></p>
<script>
function makeGreeter(greeting) {
return function (name) {
return greeting + ", " + name;
};
}
const hello = makeGreeter("Hello");
document.getElementById("demo").textContent = hello("Sam");
</script>
The inner function remembers greeting, which is a closure.
Knowledge check
1. Which keywords are block scoped?
let and const.
2. What is a closure?
A function that remembers the variables from where it was created.
3. What error appears when a variable is used outside its scope?
A ReferenceError.
Summary
- Scope controls where a variable can be used: global, function, or block.
- Prefer
letandconst, and keep variables as local as possible. - Closures let functions keep private data.