Scope is the set of rules that decides where a variable can be seen and used. A variable declared in one place might be visible everywhere, only inside one function, or only inside one pair of curly braces. Most "is not defined" errors are really scope questions.
| Scope | Created by | Visible |
|---|---|---|
| Global | Declaring outside any function or block | Everywhere |
| Function | Declaring inside a function | Only inside that function |
| Block | let / const inside { } | Only inside those braces |
const siteName = "JS Lab"; // global
function header() {
return `Welcome to ${siteName}`; // can see it
}
console.log(header());
console.log(siteName); // can see it here too
Variables declared inside a function exist only while that function runs, and only inside it:
function bake() {
const temp = 350;
return `Oven at ${temp}`;
}
console.log(bake()); // "Oven at 350"
console.log(temp); // ReferenceError: temp is not defined
let and const are limited to the nearest pair of curly braces, whether that is an if, a loop, or a plain block:
if (true) {
const secret = "inside";
console.log(secret); // "inside"
}
console.log(secret); // ReferenceError
When code uses a variable, JavaScript looks in the current scope first. If it is not there, it looks one level out, then the next, all the way to global. Inner code can see outer variables, but outer code can never see inner ones.
const planet = "Earth"; // global
function country() {
const nation = "USA"; // function scope
if (true) {
const city = "Baltimore"; // block scope
console.log(city, nation, planet); // sees all three
}
console.log(nation, planet); // sees two
// console.log(city); would be a ReferenceError
}
country();
If an inner scope declares a variable with the same name as an outer one, the inner one wins inside its scope. The outer variable is untouched:
const color = "blue";
function paint() {
const color = "red"; // shadows the outer color
return color;
}
console.log(paint()); // "red"
console.log(color); // "blue"
If you assign a value to a variable that was never declared, JavaScript quietly creates a global variable, even when the assignment is inside a function:
function myFunction() {
carName = "Volvo"; // no let, const, or var
}
myFunction();
console.log(carName); // visible out here!
This is the "automatic" declaration from JS Variables, and it is why that lesson said never to rely on it. In strict mode (JS Strict Mode), undeclared variables are not made global; the assignment throws a ReferenceError instead.
In a browser, the global scope is the window object. A global declared with var becomes a property of window; one declared with let or const does not:
var carName = "Volvo";
let carModel = "XC60";
console.log(window.carName);
console.log(window.carModel);
window's own variables and functions, and any code on the page, including other scripts, can overwrite yours. JS var/let/const shows a real example with var name.
let count = 0; // global: any code anywhere can change it
function addPoint() { count++; }
function resetScreen() { count = 0; } // oops: reused the name for something else
A variable's lifetime starts when it is declared. A function's local variables, including its parameters, are created each time the function starts and deleted when it finishes. That is why the same name can be used in different functions, and why a function never remembers its local values between calls:
function visit(name) { // name is local too, like a let inside
let count = 0;
count++;
return name + " visit #" + count;
}
console.log(visit("Ana"));
console.log(visit("Ana")); // count starts over at 0
Global variables live as long as the page does: in a browser, they are deleted when you close the tab. The next section shows the one way a local variable can outlive its function.
A function keeps access to the variables around it when it was created, even after the outer function has finished. You saw this in Function Expressions; now you know why it works:
function makeCounter() {
let n = 0; // private to this scope
return () => ++n;
}
const next = makeCounter();
console.log(next(), next(), next());
Nothing outside can reach n directly. The only way to change it is through next(). Scope turned it into a private variable.
What does this log?
let x = 1;
function test() {
let x = 2;
return x;
}
console.log(test(), x);
2 1. The inner x shadows the outer one only inside test. The global x is untouched.A variable is declared with const inside an if block. Where can it be used?
if blocklet and const are block-scoped: they exist only inside the nearest pair of curly braces.What happens?
function setup() {
score = 10;
}
setup();
console.log(score);
10. score was never declared, so the assignment made it an automatic global. In strict mode it would be a ReferenceError instead, which is the better outcome.fnVar and blockVar from outside their scopes and read the errorsmakeCounter() twice and show the two counters count independently