#Types and dynamic typing
JavaScript is dynamically typed: a variable is not bound to a type, only its current value is. The type lives on the value, and the engine checks it at the moment an operation runs — not when the code is written. Statically typed languages (Java, Kotlin, TypeScript at compile time) reject a mismatched assignment before the program starts; JavaScript happily runs it and only fails, if at all, when an operation can't be performed on the value it actually finds.
A useful mental model: a variable is a label on a slot, and the slot can hold any kind of value. Asking "what type is x?" really means "what type is the value in x's slot right now?" — which is exactly what typeof answers.
let x = 10; // number
x = "Hello"; // now a string — perfectly legal
console.log(typeof x); // "string"let x = 10creates a bindingxand puts the number10in it. Nothing records "x is a number" — only the value10carries the typenumber.x = "Hello"replaces the value in the same binding with a string. There's no type check to fail, so this is legal.typeof xinspects the current value, not the declaration, so it reports"string". A minute earlier the same expression would have returned"number".- This flexibility is why TypeScript exists: it adds the "this variable must stay a number" check at compile time, then erases it — at runtime it's still plain dynamic JavaScript.
typeofThere are 7 primitive types and everything else is an object:
| Primitive | Example | typeof |
|---|---|---|
string | "hi" | "string" |
number | 42, 3.14, NaN | "number" |
bigint | 10n | "bigint" |
boolean | true | "boolean" |
undefined | undefined | "undefined" |
null | null | "object" ⚠ |
symbol | Symbol("id") | "symbol" |
"Everything else" means plain objects, arrays, functions, dates, maps, class instances, regular expressions — all of them are objects, and all of them can have properties added and changed. Primitives can't: "abc".toUpperCase() returns a new string and leaves the original untouched.
Primitives are immutable and copied by value. Objects (including arrays and functions) are copied by reference — two variables can point at the same object.
let a = 1;
let b = a; // copy of the value
b++;
console.log(a); // 1
const o1 = { n: 1 };
const o2 = o1; // copy of the reference
o2.n++;
console.log(o1.n); // 2 — same objectlet b = acopies the value1intob's own slot. From now onaandbhave nothing to do with each other.b++changesbfrom1 → 2.astill holds its own1, soconsole.log(a)prints1.const o1 = { n: 1 }creates one object somewhere in memory and stores a reference (think: an address) to it ino1.const o2 = o1copies that reference, not the object. There is still only one object, and now two labels point at it.o2.n++follows the reference and changes the object'snfrom1 → 2. Readingo1.nfollows the same reference to the same object, so it prints2.- Note
constdidn't stop this:constprotects the bindingo2(you can't point it at a different object), not the object it points at.
The same rule applies when you pass arguments to a function. JavaScript always passes a copy of whatever is in the variable — for an object, that's a copy of the reference. People call this "pass by sharing":
function reassign(obj) {
obj = { n: 99 }; // points the local parameter somewhere else
}
function mutate(obj) {
obj.n = 99; // changes the shared object
}
const box = { n: 1 };
reassign(box);
console.log(box.n); // 1
mutate(box);
console.log(box.n); // 99reassign(box)copies the reference fromboxinto the parameterobj. Both now point at the object{ n: 1 }.- Inside,
obj = { n: 99 }makes the localobjpoint at a brand-new object.boxis a different variable and still points at the original, sobox.nis still1. mutate(box)again copies the reference intoobj. This timeobj.n = 99goes through the reference and changes the one shared object:ngoes1 → 99.box.nreads that same object, so it prints99.- This is the interview answer to "is JavaScript pass-by-reference?": no — it's pass-by-value, but for objects the value is a reference. You can mutate the caller's object, but you can't make the caller's variable point somewhere else.
typeof null, functions, arrays