Loading...
Preparing your page. This should only take a moment.
Loading...
Preparing your page. This should only take a moment.
A deep, practical guide to how JavaScript actually works
JavaScript looks simple on the surface. You can write a few lines, manipulate the DOM, fetch data, and ship features quickly. But under the hood, JavaScript has nuanced rules around memory, execution, coercion, and scope that directly affect correctness, performance, and debuggability.
This article goes step by step through the core language fundamentals that every serious JavaScript developer must understand. Not as isolated topics, but as a connected system.
JavaScript has seven primitive types and one non-primitive category.
Primitive values are immutable and stored by value.
numberstringbooleanundefinednullsymbolbigintExample:
let a = 10; let b = a; b = 20; console.log(a); // 10
Here, a and b hold independent copies of the value.
Non-primitives are objects, including:
They are stored by reference.
let obj1 = { x: 10 }; let obj2 = obj1; obj2.x = 20; console.log(obj1.x); // 20
Both variables point to the same memory location.
Key takeaway: Primitive types copy values. Objects copy references.
var, let, and constvarundefinedconsole.log(a); // undefined var a = 10;
This behavior is a common source of bugs and is why var is largely avoided today.
letlet x = 10; x = 20; // allowed
constconst y = 10; // y = 20; ❌ error
Important clarification:
const does not make objects immutable.
const user = { name: "A" }; user.name = "B"; // allowed
It only prevents reassignment of the reference.
Hoisting is JavaScript’s behavior of moving declarations to the top of the scope during compilation.
What gets hoisted:
What does not get hoisted:
Example:
console.log(a); // undefined var a = 10;
This is effectively treated as:
var a; console.log(a); a = 10;
Function declarations are fully hoisted:
sayHello(); function sayHello() { console.log("Hello"); }
Function expressions are not:
sayHi(); // error const sayHi = () => {};
The Temporal Dead Zone is the time between entering a scope and initializing a let or const variable.
console.log(a); // ReferenceError let a = 10;
The variable exists in memory, but it cannot be accessed.
Why TDZ exists:
var introducedTDZ enforces safer coding practices.
null vs undefinedundefinedlet a; console.log(a); // undefined
nulllet b = null;
Key difference:
undefined is a default statenull is an intentional decision== vs ===== (Loose Equality)0 == "0"; // true false == 0; // true null == undefined; // true
=== (Strict Equality)0 === "0"; // false
Rule of thumb:
Use === unless you have a very specific reason not to.
Loose equality introduces implicit conversions that are hard to reason about.
Type coercion is JavaScript automatically converting values from one type to another.
"5" + 1; // "51"
"5" - 1; // 4
Falsy values:
false0""nullundefinedNaNEverything else is truthy.
if ("0") { // this runs }
Understanding coercion is critical for writing predictable conditions.
typeof QuirksThe typeof operator is useful but imperfect.
typeof 10; // "number" typeof "a"; // "string" typeof true; // "boolean" typeof undefined; // "undefined" typeof function(){}; // "function"
The famous bug:
typeof null; // "object"
This is a historical bug in JavaScript that cannot be fixed without breaking the web.
Correct way to check null:
value === null;
NaN and Edge CasesNaN stands for Not a Number.
Number("abc"); // NaN
Important properties:
NaN === NaN; // false
To check NaN:
Number.isNaN(value);
Avoid:
isNaN("abc"); // true (coerces first)
Always prefer Number.isNaN.
JavaScript technically uses pass by value, but the value for objects is a reference.
function change(x) { x = 20; } let a = 10; change(a); console.log(a); // 10
function change(obj) { obj.x = 20; } let o = { x: 10 }; change(o); console.log(o.x); // 20
The reference is copied, not the object itself.
Copies only the first level.
const obj = { a: 1, b: { c: 2 } }; const copy = { ...obj }; copy.b.c = 5; console.log(obj.b.c); // 5
Methods that create shallow copies:
Object.assignArray.sliceCreates a completely independent copy.
Common approaches:
JSON.parse(JSON.stringify(obj));
Limitations:
Better approach:
structuredClone (modern browsers)lodash.cloneDeepGoal: Build a rock-solid mental model of JavaScript core language fundamentals so the language stops surprising you.