Variables and Data Types
Variables and Data Types
Variables are how a program remembers things: a user's name, a score, whether a checkbox is ticked. Before you can write anything interesting in JavaScript, you need to know how to create variables, what kinds of values they can hold, and which pitfalls catch almost every beginner. This tutorial walks through all three, step by step.
Step 1: Declaring Variables with let and const
Modern JavaScript gives you two everyday keywords: let and const.
let name = "John"; // can be reassigned later
const age = 25; // cannot be reassigned
name = "Jane"; // fine
// age = 26; // TypeError: Assignment to constant variable
Why it works this way: const does not mean "constant value forever" — it means the variable name cannot be pointed at a different value after it is created. This protects you from accidental reassignment, one of the most common sources of bugs. When the engine sees age = 26 on a const, it refuses immediately with a clear error instead of letting the bug hide.
There is an important subtlety: const locks the binding, not the contents. An object or array declared with const can still be modified internally.
const user = { name: "Ada" };
user.name = "Grace"; // allowed — we changed the object, not the binding
// user = {}; // TypeError — this would replace the binding
Step 2: Why var Is Avoided
Older code uses var, and you will still meet it in tutorials and legacy projects. It has two behaviors that cause bugs:
// 1. var ignores block scope
if (true) {
var leaky = "I escape the block";
let contained = "I stay inside";
}
console.log(leaky); // "I escape the block"
// console.log(contained); // ReferenceError// 2. var is hoisted with the value undefined
console.log(ghost); // undefined (no error!)
var ghost = "boo";
Why it works this way: var is scoped to the whole function, not the nearest { } block, and its declaration is "hoisted" to the top of the function with an initial value of undefined. let and const are also hoisted, but they sit in the temporal dead zone until their declaration line runs — accessing them early throws a ReferenceError, which is far easier to debug than a silent undefined.
Step 3: The Seven Primitive Types
JavaScript is dynamically typed: the variable has no fixed type, the value does.
let greeting = "Hello, World!"; // String
let count = 42; // Number (integers)
let price = 19.99; // Number (decimals too — one type)
let isActive = true; // Boolean
let notDefined; // undefined — declared, no value yet
let empty = null; // null — intentionally "no value"
let sym = Symbol("unique"); // Symbol (ES6) — unique identifiers
let bigNumber = 9007199254740991n; // BigInt (ES2020) — huge integers
Everything that is not a primitive — objects, arrays, functions, dates — is an object. Primitives are copied by value; objects are copied by reference, which becomes very important once you start passing data around.
The difference between undefined and null trips up many learners: undefined means "the language has not been given a value here", while null means "a programmer deliberately set this to nothing". Use null when you want to signal an intentional absence.
Step 4: Checking Types with typeof
typeof "hello" // "string"
typeof 42 // "number"
typeof true // "boolean"
typeof undefined // "undefined"
typeof null // "object" <-- famous historical bug!
typeof {} // "object"
typeof [] // "object" (arrays are objects)
typeof function(){} // "function"
Why typeof null is "object": it is a bug from the very first JavaScript implementation in 1995, kept forever because fixing it would break existing websites. Check for null with value === null instead. Similarly, arrays report "object", so use Array.isArray(value) when you need to know.
Step 5: Dynamic Typing and Coercion
Because types live on values, a variable can change type — and JavaScript will silently convert types when operators mix them:
let x = "5" + 1; // "51" — + prefers string concatenation
let y = "5" - 1; // 4 — - only works on numbers, so "5" converts
console.log(1 == "1"); // true — == coerces before comparing
console.log(1 === "1"); // false — === compares type AND value
This is why experienced developers use === and !== almost exclusively: they never coerce, so comparisons behave predictably.
Common Beginner Errors and Fixes
- Reassigning a const:
TypeError: Assignment to constant variable. Fix: declare withletif the value genuinely needs to change; otherwise restructure so it does not. - Using a variable before its declaration:
ReferenceError: Cannot access 'x' before initialization. Fix: declare variables at the top of the block where you use them. - Adding a number to a string from an input field: form values are always strings, so
"10" + 5gives"105". Fix: convert first withNumber(value)orparseInt(value, 10). - Comparing with ==:
0 == ""istrue, which almost never matches your intent. Fix: always use===. - Expecting const objects to be frozen: mutation still works. Fix: use
Object.freeze(obj)when you need real immutability at the top level.
Practice Exercise
Create a small "profile card" program:
const named username holding your name.let named loginCount starting at 0, then increment it once.null called lastError.typeof result.typeof lastError prints before you run it — then check whether you were right.const username = "your-name-here";
let loginCount = 0;
loginCount = loginCount + 1;
const lastError = null;
console.log(username, typeof username);
console.log(loginCount, typeof loginCount);
console.log(lastError, typeof lastError);
If your bonus prediction was "object", congratulations — you have already internalized JavaScript's most famous quirk.