JavaScript: Variables & Data Types
Understand how to declare and scope variables, how hoisting works, and every data type JavaScript provides.
Variable Declarations: var, let, const
JavaScript has three ways to declare variables. const is the default choice, let is for values that need reassignment, and var is legacy and should be avoided in modern code.
var / let / const
Each keyword has different scoping rules and reassignment behaviour.
- const: block-scoped, cannot be reassigned; use by default
- let: block-scoped, can be reassigned; use when value changes
- var: function-scoped, hoisted, can be re-declared; avoid in modern JS
conston an object means the binding is fixed, not the object's contents
const, let, and var
const fixes the binding, not the value inside an object.
Press Run to execute the code and see output here.
| Feature | var | let | const |
|---|---|---|---|
| Scope | Function | Block | Block |
| Hoisted | Yes (undefined) | Yes (TDZ) | Yes (TDZ) |
| Re-declarable | Yes | No | No |
| Reassignable | Yes | Yes | No |
| Use today? | ❌ Avoid | ✅ When needed | ✅ Default |
Variable Scope
Scope determines where a variable is accessible. JavaScript has three scopes: global (entire program), function (inside a function), and block (inside any {}).
The Three Scopes
Scope controls visibility and lifetime of a variable.
- Global scope, declared outside any function or block; accessible everywhere
- Function scope,
vardeclared inside a function; invisible outside it - Block scope,
let/constinside{}; invisible outside the block - Inner scopes can read outer variables, but not vice versa
Global, Function, and Block Scope
Each scope level can see its parent, but parents cannot see inward.
Press Run to execute the code and see output here.
Hoisting Behaviour
Hoisting is JavaScript's behaviour of moving declarations to the top of their scope before execution. Only the declaration is hoisted, the assignment stays where it is.
Hoisting
Declarations are processed before any code runs, assignments are not.
- var: declaration hoisted, initialised to
undefineduntil the assignment line - function declarations: fully hoisted, callable before the definition
- let / const: hoisted but not initialised; accessing them before declaration throws a ReferenceError (TDZ)
- Relying on hoisting is a code smell, always declare before use
Hoisting in Action
var gives undefined before its line; function declarations are fully available.
Press Run to execute the code and see output here.
Temporal Dead Zone (TDZ)
The Temporal Dead Zone is the region from the start of a block up to the point where a let or const is declared. Accessing the variable inside the TDZ throws a ReferenceError.
Temporal Dead Zone
let and const are hoisted but not initialised, the gap is the TDZ.
- The TDZ starts at the top of the block, not the top of the file
- Accessing a let/const variable inside the TDZ always throws a ReferenceError
- The TDZ ends exactly at the declaration line
- TDZ exists to catch bugs, it is intentional, unlike var's silent undefined
Temporal Dead Zone Demo
Accessing city before its declaration line throws, even though it is in the same block.
Press Run to execute the code and see output here.
Primitive Data Types: Overview
Primitives are immutable values stored directly in the variable. JavaScript has seven primitive types. When you assign a primitive to another variable, a copy of the value is made, they are completely independent.
The 7 Primitive Types
Primitives are copied by value, assigning one creates an independent copy.
- string: text in single, double, or backtick quotes
- number: integers, floats,
NaN, andInfinity - boolean:
trueorfalse - null: intentional absence of a value
- undefined: declared but not yet assigned
- symbol (ES6): guaranteed-unique identifier
- bigint (ES2020): integers beyond
Number.MAX_SAFE_INTEGER
String
A string is a sequence of characters used to represent text. Strings are immutable, you cannot change a character in place, but you can produce a new string from an existing one.
string
Text data, wrapped in single quotes, double quotes, or backticks.
- Single
'..'and double"..."quotes are equivalent - Backtick
`...`strings (template literals) support interpolation with${"{"}{expression}{"}"} - Strings are zero-indexed:
"hello"[0]is"h" - Key methods:
.length,.toUpperCase(),.includes(),.slice(),.trim()
String Basics
Template literals replace concatenation, cleaner and less error-prone.
Press Run to execute the code and see output here.
Number
JavaScript has a single number type for both integers and floating-point values. It also includes the special values NaN and Infinity.
number
All numeric values, integers and floats, share the same type.
- Integers and floats:
42,3.14,-7 - NaN: result of invalid arithmetic (
"abc" * 2);typeof NaN === "number" - Infinity: result of dividing by zero:
1 / 0 Number.MAX_SAFE_INTEGERis2^53 - 1, beyond this, use BigInt- Floating-point precision:
0.1 + 0.2 !== 0.3, use.toFixed()for display
Number Quirks
NaN, Infinity, and floating-point imprecision are the three number surprises to know.
Press Run to execute the code and see output here.
Boolean
A boolean has exactly two values: true or false. Booleans are the result of comparisons and drive all conditional logic. Every value in JavaScript is either truthy or falsy.
boolean
true or false, plus the concept of truthy and falsy for all other values.
- Falsy values:
false,0,"",null,undefined,NaN - Everything else is truthy, including
"0",[], and{} - Use
Boolean(value)or!!to explicitly convert to boolean - Comparison operators return booleans:
===,!==,>,<
Booleans and Truthiness
Careful: "0", [], and {} are all truthy even though they look "empty".
Press Run to execute the code and see output here.
Null
null is an intentional assignment that means "no value". It is used when you explicitly want a variable to hold nothing, as opposed to simply not having been assigned yet.
null
An explicit empty value, you set it on purpose to signal 'nothing here'.
typeof null === "object": a historic JavaScript bug; check with=== null- Use
nullto intentionally clear a variable - Different from
undefined: undefined means "never assigned"; null means "deliberately empty" - Nullish coalescing
??treats bothnullandundefinedas "no value"
null in Practice
Always check for null with === null, never with typeof.
Press Run to execute the code and see output here.
Undefined
undefined means a variable has been declared but no value has been assigned to it yet. JavaScript itself sets values to undefined automatically in several situations.
undefined
The default value JavaScript assigns when something has not been initialised.
- Declared variable with no assignment:
let x;→xisundefined - Missing function argument: calling
fn()when fn expects a param - Accessing a non-existent object property:
obj.missing - Functions with no
returnstatement returnundefined
Where undefined Appears
undefined is set by JavaScript, null is set by you. Both signal 'no value' but for different reasons.
Press Run to execute the code and see output here.
Symbol (ES6)
A Symbol is a guaranteed-unique, immutable primitive introduced in ES6. Every call to Symbol() creates a value that is never equal to anything else, including another Symbol with the same description.
symbol
A unique identifier, primarily used as non-colliding object property keys.
- Every
Symbol()call produces a unique value, even with the same description string - The description is just a label for debugging, not the value
- Used as object keys to avoid property name collisions in libraries
- Symbols are not enumerated in
for...inorObject.keys()
Symbol Uniqueness
Same description string, but id1 and id2 are never equal, uniqueness is guaranteed.
Press Run to execute the code and see output here.
BigInt (ES2020)
BigInt represents integers of arbitrary size, solving the precision problem that occurs when numbers exceed Number.MAX_SAFE_INTEGER (253 − 1).
bigint
Arbitrarily large integers, append n to a literal or use BigInt().
- Created with an
nsuffix:9007199254740993n - Cannot be mixed with regular
numberin arithmetic, must convert explicitly - Use for cryptography, financial calculations, or IDs that exceed safe integer range
typeof 1n === "bigint"
BigInt vs Number Precision
Regular numbers silently lose precision beyond MAX_SAFE_INTEGER, BigInt stays exact.
Press Run to execute the code and see output here.
Reference Data Types: Overview
Objects, arrays, and functions are reference types. Variables do not hold the value directly, they hold a reference (memory address) to it. Assigning a reference type to another variable gives both variables the same pointer.
Reference Types
Two variables can point to the same object, mutating through one affects the other.
- Object: unordered key/value pairs
- Array: ordered, indexed list (a specialised object)
- Function: callable object; first-class value in JavaScript
- Clone with spread
{...obj}or[...arr]to avoid shared-reference bugs
Objects
An object is a collection of key/value pairs. Keys are strings (or Symbols) and values can be any type, including other objects or functions.
Object
The fundamental building block for structured data in JavaScript.
- Defined with curly braces:
{ key: value } - Access with dot notation
obj.keyor bracket notationobj["key"] - Methods are functions stored as properties
Object.keys(),Object.values(),Object.entries()iterate over properties
Object Basics
Methods are just functions stored as object properties.
Press Run to execute the code and see output here.
Arrays
An array is an ordered, zero-indexed list. It is a specialised object where keys are numeric indices. Arrays can hold mixed types and have a rich set of built-in methods.
Array
An ordered list, the most common data structure in JavaScript.
- Defined with square brackets:
[1, "two", true] - Zero-indexed: first element is at index
0 - Key methods:
.push(),.pop(),.map(),.filter(),.find() - Use
Array.isArray(arr)to check,typeof []returns"object"
Array Basics
push adds to the end, map transforms every element into a new array.
Press Run to execute the code and see output here.
Functions as Reference Types
Functions in JavaScript are first-class objects, they can be stored in variables, passed as arguments, and returned from other functions. typeof fn returns "function", but functions are still reference types internally.
Function as a Value
Functions are objects, they can be assigned, passed, and returned like any value.
- A function stored in a variable is a function expression
- Passing a function as an argument makes it a callback
- Returning a function from a function is the basis of closures
typeof fn === "function", special typeof result for callable objects
Functions as First-Class Values
double is passed directly into map as a callback, no wrapper needed.
Press Run to execute the code and see output here.
Type Checking with typeof
The typeof operator returns a string describing the type of a value. It is the primary runtime type-checking tool, with two well-known quirks.
typeof Operator
Returns a string label for the operand's type, useful for runtime guards.
typeof "hi"→"string"typeof 42→"number"typeof true→"boolean"typeof undefined→"undefined"typeof null→"object", historic bug; check with=== nulltypeof []→"object", useArray.isArray()for arrays
typeof: Full Reference
null and arrays both return 'object', use dedicated checks for those two.
Press Run to execute the code and see output here.
Type Coercion and Conversion
Coercion is implicit type conversion done automatically by JavaScript. Conversion is explicit, you call a function to change the type deliberately. Coercion is a common source of surprising bugs.
Coercion vs Conversion
Implicit coercion happens silently, always prefer explicit conversion in production code.
- Implicit:
"5" + 3→"53"(number coerced to string by +) - Implicit:
"5" - 3→2(string coerced to number by -) - Explicit:
Number("5"),String(42),Boolean(0) - Use
===(strict equality) to skip coercion in comparisons
Coercion vs Explicit Conversion
The + operator is the trickiest, it concatenates if either side is a string.
Press Run to execute the code and see output here.
Type Checking with typeof
The typeof operator returns a string describing the type of a value. It is the primary tool for runtime type checking, with one well-known quirk.
typeof Operator
Returns a string label for the operand's type, useful for runtime guards.
typeof "hi"→"string"typeof 42→"number"typeof true→"boolean"typeof undefined→"undefined"typeof null→"object", historic bug, check with=== nullinsteadtypeof []→"object", useArray.isArray()to detect arrays
typeof in Practice
Always use Array.isArray() for arrays and === null for null, typeof alone is not enough.
Press Run to execute the code and see output here.
Type Coercion and Conversion
Coercion is implicit type conversion done automatically by JavaScript. Conversion is explicit, you call a function to change the type deliberately. Coercion is a common source of surprising bugs.
Coercion vs Conversion
Implicit coercion happens silently, always prefer explicit conversion in production code.
- Implicit (coercion):
"5" + 3→"53"(number coerced to string) - Implicit (coercion):
"5" - 3→2(string coerced to number for-) - Explicit conversion:
Number("5"),String(42),Boolean(0) - Use
===(strict equality) to avoid coercion in comparisons
Coercion vs Explicit Conversion
Run this to see how + behaves differently from - when a string is involved.
Press Run to execute the code and see output here.
Knowledge Check
1. Which declaration should you use by default in modern JavaScript?
2. What is the scope of a variable declared with let inside a block {}?
3. What does hoisting do to a var declaration?
4. What is the Temporal Dead Zone?
5. What does typeof null return?
6. Which of the following is a reference data type?
7. What is the result of "5" + 3 in JavaScript?
8. Which data type was introduced in ES2020 to handle integers beyond Number.MAX_SAFE_INTEGER?
9. What is the result of Boolean([]) in JavaScript?
10. Two variables point to the same object. You mutate the object through one variable. What happens to the other?
11. What makes every Symbol() call unique?