Back to Tutorials
📝 Beginner

Variables and Data Types

5 min read | Basics

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 with let if 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" + 5 gives "105". Fix: convert first with Number(value) or parseInt(value, 10).
  • Comparing with ==: 0 == "" is true, 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:

  • Declare a const named username holding your name.
  • Declare a let named loginCount starting at 0, then increment it once.
  • Declare a variable holding null called lastError.
  • Log one line describing each variable's value and its typeof result.
  • Bonus: predict what 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.