Skip to content

JavaScript lesson 2 of 9

JavaScript Variables and Data Types

Understand let and const, JavaScript's primitive types, and how typeof, undefined, and null behave when you check and convert values.

Published · Every example on this page was run before it was published.

Every program you will ever write has to remember something. A game remembers your score, a checkout page remembers the price of what is in your cart, a weather app remembers this morning's temperature. JavaScript's tool for remembering is the variable, and the kind of thing being remembered — a number, a piece of text, a yes-or-no answer — is its data type. These two ideas sit underneath every other thing you will learn, so it is worth getting them exactly right before moving on.

Declaring Variables with let and const

You create a variable with let or const, followed by a name, an equals sign, and a value. let creates a binding you can change later. const creates a binding you cannot reassign once it is set.

JavaScript
let temperature = 21.5;
const city = "Lisbon";
console.log(city);
console.log(temperature);
Output
Lisbon
21.5

Because temperature was declared with let, you are free to point it at a new value later, and JavaScript works out the right-hand side first, then attaches the name to the result:

JavaScript
let minutes = 90;
minutes = minutes + 30;
console.log(minutes);
Output
120

const, on the other hand, refuses a second assignment outright:

JavaScript
const pi = 3.14;
pi = 3.14159;
Output
TypeError: Assignment to constant variable.

That refusal only applies to the binding itself, not to whatever the binding points at. If a const holds an array or an object, you can still change what is inside it — you simply cannot make the name point at a different array or object:

JavaScript
const scores = [10, 20];
scores.push(30);
console.log(scores);
Output
[ 10, 20, 30 ]

scores never stopped pointing at the same array; the array itself just grew. Writing scores = [10, 20, 30] afterward, by contrast, would fail exactly like the pi example above, because that really would be pointing scores at a different array.

Given the choice, prefer const. Reach for let only when you already know a variable's value needs to change later, such as a running total or a loop counter. You may also see an older keyword, var, in code written before 2015 — it behaves differently in ways that cause real bugs, and modern JavaScript has no reason to use it, so this site does not either.

Naming Rules and Conventions

JavaScript enforces a short list of rules about what a name may look like. A name may contain letters, digits, dollar signs, and underscores. It may not start with a digit, and it may not contain a space, a hyphen, or most other punctuation. Names are case-sensitive, meaning score and Score are two completely different variables. Finally, a name cannot be one of JavaScript's reserved words — words such as let, if, class, and return that the language has claimed for its own grammar.

Beyond those hard rules, JavaScript programmers follow a shared convention called camelCase: the first word is lowercase, and every word after it starts with a capital letter, with no underscores or spaces at all.

JavaScript
let userName = "Ada";
let itemsInCart = 3;
let isLoggedIn = true;
console.log(userName, itemsInCart, isLoggedIn);
Output
Ada 3 true

Notice that a variable holding a true-or-false answer is conventionally named as a question the answer fits — isLoggedIn rather than login. That habit makes code read like a sentence rather than a puzzle.

Case sensitivity trips up beginners constantly, so it is worth seeing once:

JavaScript
let score = 10;
let Score = 99;
console.log(score);
console.log(Score);
Output
10
99

The Primitive Types You Meet First

Every value in JavaScript has a type, and the typeof operator tells you which one you are holding at any moment. Unlike a function, typeof does not need parentheses — it is written directly in front of the value.

JavaScript
let count = 7;
let price = 4.99;
let name = "Ada";
let isReady = true;
let result;

console.log(typeof count);
console.log(typeof price);
console.log(typeof name);
console.log(typeof isReady);
console.log(typeof result);
Output
number
number
string
boolean
undefined

Five types are on display there. number covers every kind of number JavaScript has — whole or decimal, positive or negative. Unlike some languages, JavaScript does not have a separate type for whole numbers; 7 and 7.5 are both simply number:

JavaScript
console.log(typeof 7);
console.log(typeof 7.5);
console.log(7 === 7.0);
Output
number
number
true

string is text, written inside single quotes, double quotes, or backticks. boolean holds exactly one of two values, true or false. And undefined is what you get automatically when a variable is declared but never given a value — let result; on its own creates the variable and leaves it empty, and undefined is JavaScript's own way of marking that emptiness. You did not have to write undefined anywhere; JavaScript put it there for you.

undefined Versus null

JavaScript has a second "nothing here" value, null, and the difference between the two trips up almost everyone at first. undefined means JavaScript has not been given a value yet. null means a programmer deliberately assigned "no value" on purpose.

JavaScript
let empty = null;
console.log(empty);
console.log(typeof empty);
Output
null
object

That second line is one of JavaScript's oldest quirks: typeof null reports "object", even though null is not an object in any useful sense. This is a long-standing mistake baked into the language itself, kept for backward compatibility, and every JavaScript developer simply learns to expect it. If you need to check specifically for null, compare it directly with === null rather than trusting typeof.

The two values are close enough that loose equality treats them as equal, while strict equality — which also checks the type — does not:

JavaScript
let a;
let b = null;
console.log(a == b);
console.log(a === b);
Output
true
false

As a rule, use undefined for "this has not been set up yet" and reserve null for the cases where you want to say, explicitly, "there is genuinely no value here."

Converting Between Types

A value's type does not change on its own, but you can build a new value of a different type out of it using the built-in functions Number(), String(), and Boolean(). Each one leaves its input untouched and hands back a fresh value.

JavaScript
let ageText = "34";
let age = Number(ageText);
console.log(age + 1);
console.log(typeof age);
console.log(typeof ageText);
Output
35
number
string

ageText is still the string "34" afterward; Number() did not transform it in place. This matters because converting text to a number is one of the most common conversions in real programs — anything a person types into a form arrives as a string.

JavaScript
console.log(Number("abc"));
console.log(Number("42"));
console.log(String(12) + " birds");
console.log(Boolean(0));
console.log(Boolean("hi"));
Output
NaN
42
12 birds
false
true

Number("abc") cannot make sense of letters as a number, so it returns NaN, short for "Not a Number" — a special number value that signals a failed or meaningless calculation rather than throwing an error outright. NaN is contagious: almost any arithmetic that touches it produces NaN too, which makes it worth checking for with Number.isNaN() whenever a conversion might fail.

JavaScript Is Dynamically Typed

In some languages you must declare in advance that a variable holds a number, and it holds numbers forever. JavaScript is dynamically typed: types belong to values, not to variable names, so a let variable is free to be reassigned to a value of an entirely different type at any moment.

JavaScript
let box = 42;
console.log(typeof box);
box = "forty-two";
console.log(typeof box);
box = null;
console.log(typeof box);
Output
number
string
object

This flexibility is convenient, but it moves a burden onto you: nothing warns you when a variable is carrying a different type than you assumed. The classic case is text that looks like a number. The string "3" and the number 3 are different values, and + treats them completely differently:

JavaScript
let quantity = "3";
console.log(quantity + quantity);
console.log(Number(quantity) + Number(quantity));
console.log(typeof (quantity + quantity));
Output
33
6
string

quantity + quantity concatenated two copies of the text "3" into "33", not 6. Nothing crashed and nothing was flagged — the program simply computed a different answer than a careless reader might expect, and carried on. This is exactly why any value arriving from outside your program — typed input, data from a network request, text read from a file — deserves a deliberate conversion before you do arithmetic with it.

A Worked Example

Here is a small, complete program that calculates a receipt line. It brings together let and const, descriptive camelCase names, null, conversion from text, and template literals.

JavaScript
const itemName = "Notebook";
const unitPriceText = "3.75";
const quantityText = "4";
let discountCode = null;

const unitPrice = Number(unitPriceText);
const quantity = Number(quantityText);
const subtotal = unitPrice * quantity;
const hasDiscount = discountCode !== null;

let total;
if (hasDiscount) {
  total = subtotal * 0.9;
} else {
  total = subtotal;
}

console.log(`Item: ${itemName}`);
console.log(`Unit price: ${unitPrice}`);
console.log(`Quantity: ${quantity} (${typeof quantity})`);
console.log(`Subtotal: ${subtotal}`);
console.log(`Discount applied: ${hasDiscount}`);
console.log(`Total due: ${total}`);
Output
Item: Notebook
Unit price: 3.75
Quantity: 4 (number)
Subtotal: 15
Discount applied: false
Total due: 15

Walking through it: the first four lines bind names to raw incoming data. Two of them end in Text deliberately, as a reminder to the reader that those values are strings rather than numbers — exactly the kind of data a form would hand you. discountCode is bound to null, which says "no discount was supplied," a statement undefined could have made too, but null is the clearer choice when a programmer is setting the absence on purpose.

The next block converts and calculates. Number(unitPriceText) builds the number 3.75 from the text "3.75", and Number(quantityText) builds 4 from "4". Only after both conversions is it safe to multiply them. Then discountCode !== null asks whether a code was actually supplied and stores the answer as a boolean in hasDiscount. The if statement reads that boolean and decides what total becomes — both branches are free to assign the same let variable, because total was declared once, above the if, precisely so both branches could reach it.

Notice Subtotal: 15, not 15.0 or 15.00. Since JavaScript has only one numeric type, a whole-number result simply prints as a whole number — there is no separate "this is technically a float" marker to show. The final template literal, ${typeof quantity}, proves that quantity really did become a number and not just text that looks numeric.

Common Mistakes

Redeclaring a variable with let or const

JavaScript
let count = 5;
let count = 10;
Output
SyntaxError: Identifier 'count' has already been declared

Unlike reassigning a value, declaring the same name twice with let or const in the same scope is not allowed at all. This is a SyntaxError, which means JavaScript refuses to run the file — not even the working line above the broken one executes. If you need a new value, drop the second let and just assign: count = 10;.

Reassigning a const

JavaScript
const maxUsers = 10;
maxUsers = 20;
Output
TypeError: Assignment to constant variable.

This is the single most common const-related error, and the fix is almost always to decide, honestly, whether the value was ever supposed to change. If it was, declare it with let from the start rather than switching later.

Reading a variable before its declaration runs

JavaScript
console.log(price);
let price = 9.99;
Output
ReferenceError: Cannot access 'price' before initialization

let and const variables exist in a kind of limbo, called the temporal dead zone, from the top of their scope until the line that declares them actually runs. Referring to the name anywhere in that gap is an error rather than quietly giving you undefined. In practice this almost only bites you when a variable is used on a line above where you meant to declare it — reordering the two lines fixes it completely.

Next Steps

You now have the two building blocks every JavaScript program is assembled from: names bound to values with let or const, and values that carry a type. The Two Number Sum practice problem is a natural place to apply them — it hands you numbers, asks you to combine them toward a target, and rewards clear variable names and a firm grasp of when a value is a number rather than a string. Before you attempt it, open the JavaScript playground and retype a few examples from this lesson, changing the values as you go. Try calling typeof on a result that surprises you, and try converting a string that cannot become a number, so that you recognise NaN on sight when it turns up in your own code.

When you want a harder one

Interview-style problems graded against hidden tests — a big step up from the exercises. Come back to these when the ideas in this lesson feel comfortable rather than new.