Variables & Data Types
var, let, and const, JavaScript's 7 primitive data types, how typeof works, the quirky world of type coercion, and why null !== undefined.
What is a Variable?
A variable is a named container that stores a value in memory. Think of it like a labeled box — you put something inside and refer to it later by the label. Variables are the most fundamental building block in any programming language.
In JavaScript, you declare a variable using one of three keywords: var, let, or const. Each behaves differently — and choosing the right one matters.
var is the old way and has confusing, bug-prone behavior. Modern JavaScript (ES6+) replaced it with let and const. In this course, we always use let and const — you'll understand why after this lesson.// Three ways to declare variables in JavaScript var oldName = "Alice"; // Old — avoid let score = 100; // Modern — use for reassignable values const PI = 3.14159; // Modern — use for constants (can't change) console.log(oldName); // "Alice" console.log(score); // 100 console.log(PI); // 3.14159
var, let, and const
var (Old — Avoid)
var is function-scoped, which means it ignores block boundaries like if statements and loops. It can also be redeclared, and it gets "hoisted" — moved to the top of its scope automatically, which causes surprising behavior.
var name = "Alice"; var name = "Bob"; // No error! Silently redeclared console.log(name); // "Bob" var x = 1; if (true) { var x = 2; // Same variable! var ignores block scope } console.log(x); // 2 (surprising! expected 1)
var doesn't respect block scope, a variable declared inside an if block leaks out to the surrounding function. This causes hard-to-find bugs. Modern code should always use let and const instead.let (Modern — Use This)
let is block-scoped — it lives only inside the {} where it was declared. It can be reassigned but not redeclared. Use let when you know the value will change over time.
let score = 0; score = 10; // OK: reassignment is allowed score = 25; // OK: reassignment again // let score = 20; // ERROR: can't redeclare with let if (true) { let inner = "only inside this block"; console.log(inner); // works fine here } // console.log(inner); // ERROR: inner is not defined outside the block console.log(score); // 25 — still accessible here
const (Constant — Use When Value Won't Change)
const is also block-scoped like let, but it cannot be reassigned after declaration. Use const by default — only switch to let when you know you need to reassign.
const MAX_SCORE = 100; // MAX_SCORE = 200; // ERROR: Assignment to constant variable const userName = "Ahmed"; // userName = "Sara"; // ERROR: can't reassign const // IMPORTANT: const with objects/arrays — the reference is constant, // but the contents can still be mutated! const user = { name: "Ahmed", age: 25 }; user.age = 26; // OK! Mutating the object's property console.log(user.age); // 26 const colors = ["red", "blue"]; colors.push("green"); // OK! Mutating the array console.log(colors); // ["red", "blue", "green"]
When to Use Which?
| Keyword | Scope | Reassignable | Redeclarable | Recommendation |
|---|---|---|---|---|
const |
Block | No | No | Use by default |
let |
Block | Yes | No | When value changes |
var |
Function | Yes | Yes | Avoid — legacy |
The 7 Primitive Data Types
JavaScript has 7 primitive data types. These are the building blocks of all data — every value you work with is either one of these primitives, or an object built from them.
// 1. string — text in quotes const name = "Ahmed"; const greeting = 'Hello, World!'; const template = `My name is ${name}`; // template literal // 2. number — integers and floats (same type in JS!) const age = 25; const price = 9.99; const negative = -42; const infinite = Infinity; const notANumber = NaN; // result of invalid math // 3. boolean — true or false only const isLoggedIn = true; const hasError = false; // 4. null — intentional "no value" const selectedUser = null; // 5. undefined — declared but not assigned let futureValue; console.log(futureValue); // undefined // 6. symbol — unique identifier (advanced) const id1 = Symbol("id"); const id2 = Symbol("id"); console.log(id1 === id2); // false — always unique! // 7. bigint — huge integers with n suffix const bigNumber = 9007199254740991n; console.log(typeof bigNumber); // "bigint"
The typeof Operator
The typeof operator returns a string describing the type of any value. It's extremely useful for debugging and type-checking in JavaScript.
console.log(typeof "hello"); // "string" console.log(typeof 42); // "number" console.log(typeof 3.14); // "number" (floats are numbers too!) console.log(typeof true); // "boolean" console.log(typeof undefined); // "undefined" console.log(typeof Symbol()); // "symbol" console.log(typeof 9007n); // "bigint" // THE FAMOUS JAVASCRIPT BUG: console.log(typeof null); // "object" ← this is WRONG but unfixable console.log(typeof {}); // "object" console.log(typeof []); // "object" (arrays are also objects) console.log(typeof function(){}); // "function"
typeof null === "object" is a well-known JavaScript bug from 1995. Brendan Eich has acknowledged it as a mistake, but it can never be fixed because millions of programs depend on this buggy behavior. Always check for null explicitly: if (value === null).Type Coercion — JS's Quirky Behavior
JavaScript automatically converts types when you mix them in operations — this is called implicit type coercion. It's one of the most confusing aspects of JavaScript for beginners, but once you understand it, you can avoid its traps.
// ── String + Number = String concatenation! ────── "5" + 3 // "53" (NOT 8 — string wins with +) "5" + 3 + 2 // "532" (left to right) 3 + 2 + "5" // "55" (3+2=5 first, then "5"+"5"="55") // ── Subtraction converts to number ─────────────── "5" - 3 // 2 (- always converts to number) "10" * 2 // 20 "10" / 2 // 5 "abc" - 1 // NaN (can't convert "abc" to number) // ── Boolean coercion ───────────────────────────── true + 1 // 2 (true = 1) false + 1 // 1 (false = 0) true + true // 2 // ── Comparison: loose vs strict ────────────────── "5" == 5 // true (loose == coerces types) "5" === 5 // false (strict === no coercion) 0 == false // true (0 is falsy) 0 === false // false (different types) "" == false // true (empty string is falsy)
=== instead of == prevents type coercion surprises. This is one of the most important JavaScript best practices. === checks both value AND type. The only time to use == is when you explicitly want type coercion — which is rare.null vs undefined
Both null and undefined represent "no value" — but they have very different meanings and origins. Knowing the difference prevents common bugs.
// undefined — JS says "no value was given" let username; // declared but not assigned console.log(username); // undefined function greet(name) { console.log(name); // undefined if no arg passed } greet(); // undefined // null — YOU intentionally say "no value" let loggedInUser = null; // no one is logged in yet console.log(loggedInUser); // null // Later, when someone logs in: loggedInUser = { name: "Ahmed", role: "admin" }; // Comparing null and undefined console.log(null == undefined); // true (loose — both are "empty") console.log(null === undefined); // false (strict — different types)
undefined is a box that was never filled in the first place — it was declared but JS never received a value for it.
Dynamic Typing
JavaScript is dynamically typed — a variable can hold any type, and you can change its type at any time. You don't need to declare what type a variable is; JavaScript figures it out at runtime.
// JavaScript: same variable, different types — all valid let x = 42; console.log(typeof x); // "number" x = "hello"; console.log(typeof x); // "string" x = true; console.log(typeof x); // "boolean" x = { name: "Ahmed" }; console.log(typeof x); // "object" // In Java/C++, this would be a compile error: // int x = 42; x = "hello"; // ERROR in Java // In Python, dynamic typing works similarly: // x = 42; x = "hello" # Python also allows this
Variable Naming Rules
JavaScript has strict rules about what you can name a variable, plus widely adopted conventions. Breaking the rules causes errors; ignoring conventions makes your code hard to read.
// ✅ VALID names — can start with letter, $, or _ let userName = "Ahmed"; // camelCase (JS standard) let _private = true; // underscore prefix convention let $element = null; // dollar sign (used by jQuery) const MAX_SIZE = 100; // UPPER_CASE for constants class UserProfile {} // PascalCase for classes // ❌ INVALID names — will throw SyntaxError // let 1name = "bad"; // can't start with a number // let user-name = "bad"; // hyphen is minus operator // let user name = "bad"; // no spaces allowed // let class = "bad"; // reserved keyword // 🚫 JS reserved keywords (can't use as names): // var, let, const, if, else, for, while, function, // return, class, new, this, typeof, delete, in, of... // 👍 Good descriptive names let isUserLoggedIn = true; // boolean: use is/has/can prefix let totalScore = 0; let firstName = "Ahmed"; // 👎 Bad names — avoid these let a = true; // meaningless let x1 = "Ahmed"; // what is x1? let temp = 9.99; // temp what?
Lesson Summary
Let's recap the key concepts from this lesson:
const by default, let when you need to reassign, never use var.const and let are both block-scoped. var is function-scoped and causes confusing bugs — avoid it.typeof returns a string of the type. Important bug: typeof null === "object" — always check null explicitly."5" + 3 = "53" but "5" - 3 = 2. Always use === not ==.null = you intentionally set "no value". undefined = JS never received a value. Both are "empty" but different.typeof null return in JavaScript?"5" + 3 in JavaScript?null and undefined?Now it's your turn. Apply everything from this lesson in one practical program.
Create a JavaScript file called
student.js. Declare variables to represent a complete student profile:
const— Student's full namelet— Age (a number)let— GPA (a decimal number)const— isEnrolled (boolean — true)let— favoriteSubject (a string)const— studentId (nullinitially — explain why in a comment)
console.log("Name:", name);
Finally, try reassigning the age after one year and log it again.
💡 Show hints if you're stuck
- Use
constfor things that don't change (name, enrollment status) - Use
letfor things that can change (age, GPA, favoriteSubject) nullmeans "not yet assigned" — the student ID hasn't been issued yettypeofworks on any variable:console.log(typeof age)- Try to reassign the
constname — you'll see an error! That's expected.