A variable is a name under which a program stores a value: in JavaScript you declare it with const if the value won't be reassigned and with let if it will. Every value has a type: seven primitive ones (number, string, boolean, undefined, null, bigint, symbol) plus objects, arrays included. You check the type with the typeof operator and compare values with strict === so JavaScript doesn't convert types behind your back.
After this you will be able to
- Declare variables with
constandletand explain when each is needed - Name JavaScript's seven primitive types and predict
typeofresults, including the special cases of null, arrays and NaN - Predict the result of implicit type conversion and choose
===over== - Process form data: trim spaces, convert a string to a number and check the result with
Number.isNaN
Know beforehand
Verified with
Node.js 24 LTS (24.18.0)Microsoft Edge 155
Checked against docs: October 11, 2026
Contents
A variable is a name for a value: let and const
In the first program we wrote const bill = 12500 and then used bill instead of the number. That's a variable: a name under which the program remembers a value. MDN calls variables symbolic names for values. Think of a labeled box: the name is on the lid, the value is inside. Unlike many languages, JavaScript doesn't write a type on the box: the same let variable can hold a number first and a string later.
const shopName = "Krem Coffee"; // never changes — const
let cupsSold = 0; // will change — let
cupsSold = cupsSold + 3;
cupsSold += 2; // same as cupsSold = cupsSold + 2
console.log(shopName); // → Krem Coffee
console.log(cupsSold); // → 5
let discount; // declared but not assigned
console.log(discount); // → undefinedIn programming, = doesn't mean “equals” but “assign”: evaluate what's on the right and store it under the name on the left. So cupsSold = cupsSold + 3 reads as “take the current value, add three and write it back”. += is shorthand for the same thing. A variable declared with let and no value holds undefined, meaning “nothing has been assigned yet”.
const forbids assigning a new value. Trying to do so is a runtime error:
const vatRate = 12;
vatRate = 16;
console.log(vatRate);$ node const-error.js
…\first-js\const-error.js:2
vatRate = 16;
^
TypeError: Assignment to constant variable.
at …
Node.js v24.18.0const
- Can be reassigned
- No
- Where the variable is visible
- Inside the { } block where it's declared
- When to use
- By default, for anything that isn't reassigned
let
- Can be reassigned
- Yes
- Where the variable is visible
- Inside the { } block where it's declared
- When to use
- Counters, running totals, values that change
var
- Can be reassigned
- Yes
- Where the variable is visible
- Throughout the function, not the block
- When to use
- The old way: you'll see it in other people's code, new code doesn't need it
- A name starts with a letter,
_or$; after that, digits are allowed too:total2works,2totaldoesn't. - Case matters:
totalandTotalare two different variables. - You can't use the language's reserved words as names:
let,const,if,return,classand others. - By convention, JavaScript names use camelCase:
cupsSold,deliveryPrice. It's not a language rule, but almost all the code you'll meet is written that way.
Primitives: seven simple types
The ECMAScript standard defines eight data types: seven primitives and the object. A primitive is a simple, immutable value: a number, a string, a boolean. “Immutable” means you can't edit a string in place: string methods return a new string and the original stays as it was.
number
- Example
- 12500, 0.5, -3, NaN
- typeof
- "number"
- What it's for
- All numbers, whole and fractional
string
- Example
- "Almaty", 'coffee', a template in backticks
- typeof
- "string"
- What it's for
- Text
boolean
- Example
- true, false
- typeof
- "boolean"
- What it's for
- Yes or no: is the order paid, is the item in stock
undefined
- Example
- undefined
- typeof
- "undefined"
- What it's for
- No value has been assigned
null
- Example
- null
- typeof
- "object"
- What it's for
- Intentionally empty: “no phone number”
bigint
- Example
- 9007199254740993n
- typeof
- "bigint"
- What it's for
- Very large integers
symbol
- Example
- Symbol("id")
- typeof
- "symbol"
- What it's for
- Unique keys; beginners rarely need them
console.log(typeof 12500); // → number
console.log(typeof 0.5); // → number
console.log(typeof "Almaty"); // → string
console.log(typeof true); // → boolean
console.log(typeof undefined); // → undefined
console.log(typeof null); // → object
console.log(typeof 9007199254740993n); // → bigint
console.log(typeof Symbol("id")); // → symbol
console.log(typeof { id: 1042 }); // → object
console.log(typeof [1, 2, 3]); // → object
console.log(Array.isArray([1, 2, 3])); // → true
console.log(typeof NaN); // → numberThree results are worth remembering. typeof null gives "object", a leftover from the very first implementation of JavaScript that has stayed in the language; MDN advises checking for null with value === null. An array is also "object" to typeof; Array.isArray tells it apart. And NaN, “not a number”, is formally of type number: it's a special numeric value you get when a calculation fails.
Objects and arrays are reference types
An object is a set of key–value pairs: an order with a number, an amount and a status. An array is an ordered list: the lines on a receipt, a client's phone numbers. Both are objects, and an important rule applies to them: a variable holds not the object itself but a reference to it. Assign the object to another variable and no copy appears; both variables point to the same thing.
const order = { id: 1042, total: 13750, status: "new" };
order.status = "paid"; // const doesn't stop you changing the contents
console.log(order.status); // → paid
const sameOrder = order; // a second reference to the same object
sameOrder.total = 0;
console.log(order.total); // → 0
const copy = { ...order }; // a new object with the same properties
copy.total = 9990;
console.log(order.total); // → 0
console.log(copy.total); // → 9990
console.log([1, 2] === [1, 2]); // → false
console.log(sameOrder === order); // → trueThis also explains how const behaves with objects. As MDN explains, const prevents reassignment, not mutation: you can't replace the object as a whole, but you can change its properties. To get an independent copy, use the { ...order } syntax. The copy is shallow, though: nested objects inside are still shared.
Type conversion: == vs ===
JavaScript is dynamically typed: you don't declare a variable's type up front, and values are converted automatically when needed. That's convenient as long as the conversion happens where you expect it. The main trap is plus: if at least one operand is a string, + joins strings. The other arithmetic operators do the opposite and turn strings into numbers.
// Implicit conversion
console.log("37" + 7); // → 377
console.log("37" - 7); // → 30
console.log("5" * "2"); // → 10
// Explicit conversion
console.log(Number("12500")); // → 12500
console.log(Number(" 42 ")); // → 42
console.log(Number("12 500")); // → NaN
console.log(Number("")); // → 0
console.log(Number(true)); // → 1
console.log(parseInt("12px", 10)); // → 12
console.log(String(42) + "1"); // → 421
console.log(Boolean("")); // → false
console.log(Boolean("0")); // → trueIt's safer to convert explicitly: Number(value), String(value), Boolean(value). Watch out for two traps. Number("") gives 0, not NaN, so an empty form field silently becomes zero. And Number("12 500") gives NaN: a space inside a number isn't allowed. If a string starts with a number followed by text, as in "12px", use parseInt; MDN recommends always passing the radix, 10, as its second argument.
console.log(0 == "0"); // → true
console.log(0 === "0"); // → false
console.log("" == 0); // → true
console.log("" === 0); // → false
console.log(null == undefined); // → true
console.log(null === undefined); // → false
console.log(1 === 1.0); // → true
console.log("Alma" === "alma"); // → false== (loose equality)
- Converts values to a common type before comparing
- 0 == "0" and "" == 0 are true
- The conversion rules are long and non-obvious
- Bugs show up later, on rare data
=== (strict equality)
- Different types are immediately false, no conversion
- 0 === "0" is false
- The result is easy to predict
- Its “not equal” partner is !==
Strings: templates and useful methods
You can write a string in double quotes "…", single quotes '…' or backticks (usually the key to the left of 1). Backticks make a template literal: values are inserted with ${expression}, and it can span several lines. A string has a length and dozens of methods; here are the ones you'll need most often when working with form data.
const rawName = " aliya ";
const city = "Almaty";
const clientName = rawName.trim();
console.log(clientName.length); // → 5
console.log(clientName.toUpperCase()); // → ALIYA
console.log(clientName[0].toUpperCase() + clientName.slice(1)); // → Aliya
console.log(`Client: ${clientName}, ${city}`); // → Client: aliya, Almaty
console.log(`[${rawName}]`); // → [ aliya ]
const phone = "+7 701 123 45 67";
console.log(phone.replaceAll(" ", "")); // → +77011234567
console.log(phone.includes("701")); // → true
console.log(phone.at(-1)); // → 7
console.log(String(7).padStart(3, "0")); // → 007trim()
- What it does
- Removes spaces at both ends
- Example
- " aliya ".trim() → "aliya"
toUpperCase() / toLowerCase()
- What it does
- Changes case
- Example
- "aliya".toUpperCase() → "ALIYA"
slice(start, end)
- What it does
- Cuts out part of a string
- Example
- "Almaty".slice(0, 3) → "Alm"
includes(text)
- What it does
- Checks whether a substring is present
- Example
- "+7 701…".includes("701") → true
replaceAll(what, with)
- What it does
- Replaces every occurrence
- Example
- "1 2 3".replaceAll(" ", "") → "123"
at(index)
- What it does
- Character by position; negative counts from the end
- Example
- "coffee".at(-1) → "e"
padStart(length, char)
- What it does
- Pads on the left to a given length
- Example
- "7".padStart(3, "0") → "007"
Common traps: NaN, 0.1 + 0.2, undefined
// NaN isn't equal even to itself
const qty = Number("three");
console.log(qty); // → NaN
console.log(qty === NaN); // → false
console.log(Number.isNaN(qty)); // → true
// Fractions are stored in binary, approximately
console.log(0.1 + 0.2); // → 0.30000000000000004
console.log(0.1 + 0.2 === 0.3); // → false
console.log((0.1 + 0.2).toFixed(2)); // → 0.30
// Money is easier to handle in whole minor units: tiyn, cents
const priceTiyn = 199990; // 1,999.90 ₸
const totalTiyn = priceTiyn * 3;
console.log(totalTiyn / 100); // → 5999.7
// Integers above 2^53 − 1 lose precision — use BigInt for them
console.log(Number.MAX_SAFE_INTEGER); // → 9007199254740991
console.log(9007199254740993); // → 9007199254740992
console.log(9007199254740993n + 1n); // → 9007199254740994n
// undefined means "no value", e.g. a property that doesn't exist
const user = { name: "Aliya" };
console.log(user.phone); // → undefinedNaNis the only value that isn't equal to itself, soqty === NaNis alwaysfalse. Check withNumber.isNaN(qty).0.1 + 0.2isn't0.3: numbers are stored in the binary IEEE 754 format, and 0.1 can't be written exactly in binary, just as 1/3 can't in decimal. It's a property of the format, not a JavaScript bug; other languages using this format behave the same way.toFixed(2)rounds for display and returns a string, not a number: use it when printing, not in calculations.- Integers are stored exactly only up to
Number.MAX_SAFE_INTEGER(2^53 − 1). Beyond that you needBigInt, a number ending inn; you can't mix BigInt and regular numbers in arithmetic, that throws a TypeError. undefinedis what you get when you read a property that doesn't exist. You setnullyourself when you want to say “no value, on purpose”.
Practice: predict the output
You now know how to store values and predict what they'll turn into. The next lesson is conditions and loops: the program starts making decisions, such as rejecting a NaN quantity, and we'll look at which values JavaScript treats as “falsy”. Static types that catch errors before the code even runs come with TypeScript, which appears later in the track.
How this was verified3 · passedchecked 11 October 2026
“Run” means the code was executed in a scratch project or container and the output in the article comes from that run. “Partial” means it was checked against stubs instead of external services. “Not run” means it needs a device, an account or a key; the steps were checked against the official documentation. The verification project files and run logs are kept in the InterLAB archive.