Values, variables and scopes
Language foundations14 min readLesson 1 of 4
1.1 What JavaScript is
JavaScript is the programming language of the web page. A browser downloads a script, runs it in a sandbox tied to the page, and lets it read and change the document. The same language also runs outside the browser through Node.js, which is why a script that only uses the console, strings, numbers and functions behaves the same in both places.
The language belongs to the ECMAScript standard. Browsers add the web platform on top: the document, events, timers, fetch, storage. In this course you start with the language itself, then move to the browser APIs that use it.
A JavaScript program is a list of statements. The browser runs them in order until the script ends or an error stops it. A function call packs a block of statements under a name so the block can run later, and that idea carries through every later module.
1.2 Running a script
The smallest useful script prints a value. console.log writes to the developer console in a browser or to the terminal in Node. Open the browser developer tools with F12, choose the Console tab, and type a statement to run it immediately against the current page.
console.log("Hello from JavaScript");
console.log(2 + 3);Output
Hello from JavaScript 5
1.3 Statements and blocks
A statement is one complete instruction. A declaration creates a name, an expression statement evaluates an expression and discards the result, and a control statement chooses what runs next. Most lines in a beginner script are expression statements wrapped around a function call.
A block is a pair of braces holding statements. Blocks appear after if, for and while, inside functions, and on their own. A bare block is legal and creates a scope, which is occasionally useful for limiting the lifetime of a temporary name.
JavaScript allows automatic semicolon insertion, so the parser adds semicolons in many line breaks. Relying on that rule creates traps around return statements and lines starting with parentheses or brackets. Write the semicolons yourself, keep one statement per line, and the parser has less to guess.
A function is the reusable version of a block. It stores statements under a name, takes parameters, and can return a value. The next module covers functions in detail, but every script in this module already uses one: console.log is a function call.
A file version is the same code stored with a .js extension and loaded with a script tag. Place the tag at the end of the body, or add the defer attribute, so the browser parses the page before the script asks for elements. A module script behaves differently: it runs after parsing and keeps its top-level names out of the global scope, a detail module 6 returns to.
Comments explain intent and never run. A double slash starts a single-line comment, and slash-star opens a block comment that ends with star-slash.
1.4 Declaring variables
A variable is a named box for a value. Modern JavaScript has two ways to declare one. let creates a binding that can be reassigned. const creates a binding that cannot be reassigned after it is initialised. Both are block scoped, meaning the name exists only inside the nearest pair of braces.
A const binding holds its reference still, not the value itself. A constant array can still be mutated with push, and a constant object can have properties changed. What const forbids is pointing the name at a different value.
let score = 10;
score = score + 5;
const name = "Aarav";
console.log(`${name} scored ${score}`);Output
Aarav scored 15
Choose const by default and switch to let only when the name must be reassigned. This habit makes a reader ask fewer questions about where a value changes. Declaring a name twice in the same scope is an error, and using a const name before its declaration throws a ReferenceError because the binding starts in a temporary dead zone.
1.5 How the engine prepares a script
Before the first line runs, the parser reads the whole script and builds a tree. The engine then creates the top-level scope and registers the declarations it found. Function declarations are available before their line, so a call higher in the file still works. var names are also registered early but start as undefined.
let and const names are registered early too, yet they stay unusable until their declaration line. That is the temporary dead zone again, seen from the engine side. The rule exists so a typo in a name cannot silently read undefined from an unrelated earlier line.
The execution phase then walks the tree from top to bottom, runs each statement and evaluates each expression. A runtime error stops the script at the failing statement. Code after the error does not run, and an uncaught error appears in the console with a stack trace. Reading that trace from the bottom up usually finds the original cause first.
1.6 Scope in practice
Scope is the set of names a line of code can see. JavaScript looks for a name in the current block, then in each enclosing block, then in the function, and finally in the global scope. The first match wins, so a name can be deliberately shadowed by an inner block.
Shadowing is legal and sometimes useful, but an accidental shadow hides a value that the rest of the function needed. Give variables specific names and keep blocks short when the scope game starts to feel like a puzzle.
const level = "outer";
if (true) {
const level = "inner";
console.log(level);
}
console.log(level);
function showScope() {
const message = "inside function";
console.log(message);
}
showScope();Output
inner outer inside function
A block is any pair of braces that introduces a scope: an if body, a for loop body, a bare block. Function parameters live in the function scope. A name declared in an inner block is not visible outside it, and a missing declaration is caught when the script reaches that line rather than when it is parsed.
The temporary dead zone matters in interviews. let and const bindings exist from the start of their block, but reading one before the declaration throws instead of returning undefined. The error name is ReferenceError, which is a better signal than a silent missing value.
try {
console.log(ready);
let ready = true;
} catch (error) {
console.log(error.name);
}Output
ReferenceError
1.7 var and why modern code avoids it
Before 2015 the only declaration was var. A var name ignores blocks and belongs to the nearest function, so a variable created inside an if statement leaks into the whole function. That behaviour caused many accidental globals in older code, and the flexible scope makes the code harder to reason about.
var is not broken, and you will meet it in old libraries. For new code, use let and const. They express the intended scope, and the temporary dead zone turns early use into an error instead of a surprise.
function demoVar() {
if (true) {
var leaked = "var leaks out of the block";
}
console.log(leaked);
}
demoVar();Output
var leaks out of the block
1.8 Naming and constants
Names use letters, digits, dollar signs and underscores. A name cannot start with a digit, cannot be a reserved word such as class or return, and is case sensitive, so total and Total are different names. Use camelCase for ordinary variables and UPPER_SNAKE_CASE for values that really are constants by convention, such as limits and rates.
Prefer descriptive names over comments. secondsLeft explains more than s. Avoid single-letter names outside loop counters, and avoid abbreviations that only the author understands.
1.9 Common mistakes
- Reassigning a
constname. The error isTypeError: Assignment to constant variable. - Using a
letname before its declaration. The binding is in the temporary dead zone. - Leaking a value with
varand expecting block scope. - Declaring a global by writing
total = 10with no declaration. In strict mode this throws. - Relying on a loop variable after the loop, when that variable was declared with
letinside the loop.
Exam
Scope questions usually ask what a script prints, not what a variable means. Read each block, write the path the interpreter takes, and check the declaration keyword before deciding whether an inner name shadows an outer one.
- Declare a `const` name and a `let` name, then log both.
- Predict the output of the shadowing example before running it.
- Explain the difference between block scope and function scope out loud.
- Rewrite one `var` example with `let` and check that the scope changes.
