diff --git a/README.md b/README.md
index f1b53cca..c98adf5b 100644
--- a/README.md
+++ b/README.md
@@ -35,8 +35,8 @@ This repository helps developers master core JavaScript concepts. Each concept i
- **[Primitive Types](https://33jsconcepts.com/concepts/primitive-types)**
Learn JavaScript's 7 primitive types: string, number, bigint, boolean, undefined, null, and symbol. Understand immutability, typeof quirks, and autoboxing.
-- **[Value vs Reference Types](https://33jsconcepts.com/concepts/value-reference-types)**
- Learn how value types and reference types work in JavaScript. Understand how primitives and objects are stored, why copying objects shares references, and how to avoid mutation bugs.
+- **[Primitives vs Objects](https://33jsconcepts.com/concepts/primitives-objects)**
+ Learn how JavaScript primitives and objects differ in behavior. Understand immutability, call-by-sharing semantics, why mutation works but reassignment doesn't, and how V8 actually stores values.
- **[Type Coercion](https://33jsconcepts.com/concepts/type-coercion)**
Learn JavaScript type coercion and implicit conversion. Understand how values convert to strings, numbers, and booleans, the 8 falsy values, and how to avoid common coercion bugs.
diff --git a/docs/beyond/concepts/blob-file-api.mdx b/docs/beyond/concepts/blob-file-api.mdx
index a574f015..12ade561 100644
--- a/docs/beyond/concepts/blob-file-api.mdx
+++ b/docs/beyond/concepts/blob-file-api.mdx
@@ -1,5 +1,5 @@
---
-title: "Blob & File API: Working with Binary Data in JavaScript"
+title: "Blob & File API in JavaScript"
sidebarTitle: "Blob & File API"
description: "Learn JavaScript Blob and File APIs for binary data. Create, read, and manipulate files, handle uploads, generate downloads, and work with FileReader."
---
diff --git a/docs/beyond/concepts/computed-property-names.mdx b/docs/beyond/concepts/computed-property-names.mdx
index b6fff4b9..bd61692d 100644
--- a/docs/beyond/concepts/computed-property-names.mdx
+++ b/docs/beyond/concepts/computed-property-names.mdx
@@ -1,5 +1,5 @@
---
-title: "Computed Property Names: Dynamic Object Keys in JavaScript"
+title: "Computed Property Names in JS"
sidebarTitle: "Computed Property Names"
description: "Learn JavaScript computed property names. Create dynamic object keys with variables, expressions, Symbols, and computed methods for cleaner ES6+ code."
---
diff --git a/docs/beyond/concepts/cookies.mdx b/docs/beyond/concepts/cookies.mdx
index 82104fc7..e3e5126d 100644
--- a/docs/beyond/concepts/cookies.mdx
+++ b/docs/beyond/concepts/cookies.mdx
@@ -1,5 +1,5 @@
---
-title: "Cookies: Server-Accessible Browser Storage in JavaScript"
+title: "Cookies in JavaScript"
sidebarTitle: "Cookies"
description: "Learn JavaScript cookies. Understand how to read, write, and delete cookies, cookie attributes like HttpOnly and SameSite, and security best practices."
---
diff --git a/docs/beyond/concepts/custom-events.mdx b/docs/beyond/concepts/custom-events.mdx
index 28bfd02b..90fe0af8 100644
--- a/docs/beyond/concepts/custom-events.mdx
+++ b/docs/beyond/concepts/custom-events.mdx
@@ -1,7 +1,7 @@
---
-title: "Custom Events: Create Your Own Events in JavaScript"
+title: "Custom Events in JavaScript"
sidebarTitle: "Custom Events"
-description: "Learn JavaScript custom events. Create, dispatch, and listen for CustomEvent, pass data with the detail property, and build decoupled event-driven architectures."
+description: "Learn JavaScript custom events. Create and dispatch CustomEvent, pass data with detail, and build event-driven architectures."
---
What if you could create your own events, just like `click` or `submit`? What if a shopping cart could announce "item added!" and any part of your app could listen and respond? How do you build components that communicate without knowing about each other?
diff --git a/docs/beyond/concepts/debouncing-throttling.mdx b/docs/beyond/concepts/debouncing-throttling.mdx
index 073218b8..1b67405e 100644
--- a/docs/beyond/concepts/debouncing-throttling.mdx
+++ b/docs/beyond/concepts/debouncing-throttling.mdx
@@ -1,5 +1,5 @@
---
-title: "Debouncing & Throttling: Control Event Frequency in JS"
+title: "Debouncing & Throttling in JS"
sidebarTitle: "Debouncing & Throttling: Control Event Frequency"
description: "Learn debouncing and throttling in JavaScript. Optimize event handlers, reduce API calls, and implement both patterns from scratch with real-world examples."
---
diff --git a/docs/beyond/concepts/event-bubbling-capturing.mdx b/docs/beyond/concepts/event-bubbling-capturing.mdx
index a423b8a1..9d798555 100644
--- a/docs/beyond/concepts/event-bubbling-capturing.mdx
+++ b/docs/beyond/concepts/event-bubbling-capturing.mdx
@@ -1,5 +1,5 @@
---
-title: "Event Bubbling & Capturing: Event Propagation in JavaScript"
+title: "Event Bubbling & Capturing"
sidebarTitle: "Event Bubbling & Capturing"
description: "Learn event bubbling and capturing in JavaScript. Understand the three phases of event propagation, stopPropagation, and when to use capturing vs bubbling."
---
diff --git a/docs/beyond/concepts/event-delegation.mdx b/docs/beyond/concepts/event-delegation.mdx
index dc641014..b7e59c6d 100644
--- a/docs/beyond/concepts/event-delegation.mdx
+++ b/docs/beyond/concepts/event-delegation.mdx
@@ -1,5 +1,5 @@
---
-title: "Event Delegation: Handle Events Efficiently in JavaScript"
+title: "Event Delegation in JavaScript"
sidebarTitle: "Event Delegation"
description: "Learn event delegation in JavaScript. Handle events efficiently using bubbling, manage dynamic elements, reduce memory usage, and implement common patterns."
---
diff --git a/docs/beyond/concepts/garbage-collection.mdx b/docs/beyond/concepts/garbage-collection.mdx
index f8e7e53e..fc8be733 100644
--- a/docs/beyond/concepts/garbage-collection.mdx
+++ b/docs/beyond/concepts/garbage-collection.mdx
@@ -1,5 +1,5 @@
---
-title: "Garbage Collection in JavaScript: How Memory is Freed Automatically"
+title: "JavaScript Garbage Collection"
sidebarTitle: "Garbage Collection"
description: "Learn how JavaScript garbage collection works. Understand mark-and-sweep, reachability, and how to write memory-efficient code that helps the engine."
---
@@ -767,8 +767,8 @@ For most applications, `WeakMap` and `WeakSet` are better choices. They allow ob
Data structures with weak references that allow keys to be garbage collected when no other references exist.
-
- How JavaScript stores primitives vs objects, and why references matter for garbage collection.
+
+ How JavaScript primitives and objects behave differently, and why references matter for garbage collection.
diff --git a/docs/beyond/concepts/getters-setters.mdx b/docs/beyond/concepts/getters-setters.mdx
index 3d274912..0123879d 100644
--- a/docs/beyond/concepts/getters-setters.mdx
+++ b/docs/beyond/concepts/getters-setters.mdx
@@ -1,5 +1,5 @@
---
-title: "Getters & Setters: Computed Properties in JavaScript"
+title: "Getters & Setters in JavaScript"
sidebarTitle: "Getters & Setters: Computed Properties"
description: "Learn JavaScript getters and setters. Create computed properties, validate data on assignment, and build encapsulated objects with get and set accessors."
---
diff --git a/docs/beyond/concepts/hoisting.mdx b/docs/beyond/concepts/hoisting.mdx
index ea2f0293..5798a96d 100644
--- a/docs/beyond/concepts/hoisting.mdx
+++ b/docs/beyond/concepts/hoisting.mdx
@@ -1,7 +1,7 @@
---
-title: "Hoisting: How Declarations Move to the Top in JavaScript"
+title: "Hoisting in JavaScript"
sidebarTitle: "Hoisting: How Declarations Move to the Top"
-description: "Learn JavaScript hoisting and how declarations are moved to the top of their scope. Understand var vs let vs const hoisting, function hoisting, the Temporal Dead Zone, and common pitfalls."
+description: "Learn JavaScript hoisting: how var, let, const, and function declarations are moved to the top of their scope. Understand the Temporal Dead Zone."
---
Why can you call a function before it appears in your code? Why does `var` give you `undefined` instead of an error, while `let` throws a `ReferenceError`? How does JavaScript seem to know about variables before they're declared?
diff --git a/docs/beyond/concepts/indexeddb.mdx b/docs/beyond/concepts/indexeddb.mdx
index d01b2e0c..5bedc9b4 100644
--- a/docs/beyond/concepts/indexeddb.mdx
+++ b/docs/beyond/concepts/indexeddb.mdx
@@ -1,5 +1,5 @@
---
-title: "IndexedDB: Client-Side Database Storage in JavaScript"
+title: "IndexedDB in JavaScript"
sidebarTitle: "IndexedDB: Client-Side Database Storage"
description: "Learn IndexedDB for client-side storage in JavaScript. Store structured data, create indexes, perform transactions, and build offline-capable apps."
---
diff --git a/docs/beyond/concepts/intersection-observer.mdx b/docs/beyond/concepts/intersection-observer.mdx
index ab5c7d5d..f66ffb52 100644
--- a/docs/beyond/concepts/intersection-observer.mdx
+++ b/docs/beyond/concepts/intersection-observer.mdx
@@ -1,7 +1,7 @@
---
title: "Intersection Observer in JavaScript"
sidebarTitle: "Intersection Observer"
-description: "Learn the Intersection Observer API in JavaScript. Detect element visibility, implement lazy loading, infinite scroll, and scroll animations efficiently without scroll events."
+description: "Learn the Intersection Observer API in JavaScript. Implement lazy loading, infinite scroll, and scroll animations without scroll events."
---
How do you know when an element scrolls into view? How can you lazy-load images only when they're about to be seen? How do infinite-scroll feeds know when to load more content? And how can you trigger animations at just the right moment as users scroll through your page?
diff --git a/docs/beyond/concepts/javascript-type-nuances.mdx b/docs/beyond/concepts/javascript-type-nuances.mdx
index e9777fde..16e8f440 100644
--- a/docs/beyond/concepts/javascript-type-nuances.mdx
+++ b/docs/beyond/concepts/javascript-type-nuances.mdx
@@ -1,5 +1,5 @@
---
-title: "Type Nuances: null, undefined, typeof, and More in JavaScript"
+title: "JavaScript Type Nuances"
sidebarTitle: "Type Nuances"
description: "Learn JavaScript type nuances: null vs undefined, typeof quirks, nullish coalescing (??), optional chaining (?.), Symbols, and BigInt for large integers."
---
diff --git a/docs/beyond/concepts/json-deep-dive.mdx b/docs/beyond/concepts/json-deep-dive.mdx
index 1223f046..a0b2ed9b 100644
--- a/docs/beyond/concepts/json-deep-dive.mdx
+++ b/docs/beyond/concepts/json-deep-dive.mdx
@@ -1,5 +1,5 @@
---
-title: "JSON Deep Dive: Advanced Serialization in JavaScript"
+title: "JSON Deep Dive in JavaScript"
sidebarTitle: "JSON: Beyond Parse and Stringify"
description: "Learn advanced JSON in JavaScript. Understand JSON.stringify() replacers, JSON.parse() revivers, circular reference handling, and custom toJSON methods."
---
diff --git a/docs/beyond/concepts/localstorage-sessionstorage.mdx b/docs/beyond/concepts/localstorage-sessionstorage.mdx
index a62a424f..009dc6b3 100644
--- a/docs/beyond/concepts/localstorage-sessionstorage.mdx
+++ b/docs/beyond/concepts/localstorage-sessionstorage.mdx
@@ -1,5 +1,5 @@
---
-title: "localStorage & sessionStorage: Web Storage in JavaScript"
+title: "localStorage & sessionStorage"
sidebarTitle: "localStorage & sessionStorage"
description: "Master Web Storage APIs in JavaScript. Learn localStorage vs sessionStorage, JSON serialization, storage events, security best practices, and when to use each."
---
diff --git a/docs/beyond/concepts/memoization.mdx b/docs/beyond/concepts/memoization.mdx
index 6818356b..e359a754 100644
--- a/docs/beyond/concepts/memoization.mdx
+++ b/docs/beyond/concepts/memoization.mdx
@@ -1,5 +1,5 @@
---
-title: "Memoization: Caching Function Results in JavaScript"
+title: "Memoization in JavaScript"
sidebarTitle: "Memoization: Caching Function Results"
description: "Learn memoization in JavaScript. Cache function results, optimize expensive computations, build your own memoize function, and know when caching helps vs hurts."
---
diff --git a/docs/beyond/concepts/memory-management.mdx b/docs/beyond/concepts/memory-management.mdx
index 7421fcd2..44600e5d 100644
--- a/docs/beyond/concepts/memory-management.mdx
+++ b/docs/beyond/concepts/memory-management.mdx
@@ -1,5 +1,5 @@
---
-title: "Memory Management: How JavaScript Allocates and Frees Memory"
+title: "JavaScript Memory Management"
sidebarTitle: "Memory Management"
description: "Learn how JavaScript manages memory automatically. Understand the memory lifecycle, stack vs heap, common memory leaks, and how to profile memory with DevTools."
---
diff --git a/docs/beyond/concepts/mutation-observer.mdx b/docs/beyond/concepts/mutation-observer.mdx
index 6b3290f8..8b86d43c 100644
--- a/docs/beyond/concepts/mutation-observer.mdx
+++ b/docs/beyond/concepts/mutation-observer.mdx
@@ -1,7 +1,7 @@
---
-title: "MutationObserver: Watching DOM Changes in JavaScript"
+title: "MutationObserver in JavaScript"
sidebarTitle: "MutationObserver: Watching DOM Changes"
-description: "Learn the MutationObserver API in JavaScript. Understand how to watch DOM changes, detect attribute modifications, observe child elements, and build reactive UIs without polling."
+description: "Learn the MutationObserver API in JavaScript. Watch DOM changes, detect attribute modifications, and build reactive UIs."
---
How do you know when something changes in the DOM? What if you need to react when a third-party script adds elements, when user input modifies content, or when attributes change dynamically?
diff --git a/docs/beyond/concepts/object-methods.mdx b/docs/beyond/concepts/object-methods.mdx
index 2abafa14..6e9a7f1f 100644
--- a/docs/beyond/concepts/object-methods.mdx
+++ b/docs/beyond/concepts/object-methods.mdx
@@ -1,5 +1,5 @@
---
-title: "Object Methods: Inspecting and Transforming Objects in JavaScript"
+title: "JavaScript Object Methods"
sidebarTitle: "Object Methods: Inspect & Transform"
description: "Learn JavaScript Object methods. Master Object.keys(), values(), entries(), assign(), structuredClone(), hasOwn(), and groupBy() for object manipulation."
---
diff --git a/docs/beyond/concepts/performance-observer.mdx b/docs/beyond/concepts/performance-observer.mdx
index 810a76c4..da4592b1 100644
--- a/docs/beyond/concepts/performance-observer.mdx
+++ b/docs/beyond/concepts/performance-observer.mdx
@@ -1,7 +1,7 @@
---
-title: "Performance Observer: Monitor Web Performance in JavaScript"
+title: "PerformanceObserver in JS"
sidebarTitle: "Performance Observer"
-description: "Learn the Performance Observer API in JavaScript. Understand how to measure page performance, track Long Tasks, monitor layout shifts, and collect Core Web Vitals metrics for real user monitoring."
+description: "Learn the Performance Observer API in JavaScript. Measure page performance, track Long Tasks, and collect Core Web Vitals metrics."
---
How do you know if your website is actually fast for real users? You might run Lighthouse once, but what about the thousands of visitors with different devices, network conditions, and usage patterns? Without real-time performance monitoring, you're flying blind.
diff --git a/docs/beyond/concepts/property-descriptors.mdx b/docs/beyond/concepts/property-descriptors.mdx
index acb728d8..ba62aa05 100644
--- a/docs/beyond/concepts/property-descriptors.mdx
+++ b/docs/beyond/concepts/property-descriptors.mdx
@@ -1,5 +1,5 @@
---
-title: "Property Descriptors: Hidden Property Flags in JavaScript"
+title: "Property Descriptors in JS"
sidebarTitle: "Property Descriptors: Hidden Property Flags"
description: "Learn JavaScript property descriptors. Understand writable, enumerable, configurable flags, Object.defineProperty(), and how to create immutable properties."
---
diff --git a/docs/beyond/concepts/proxy-reflect.mdx b/docs/beyond/concepts/proxy-reflect.mdx
index 21537825..c5f62ee4 100644
--- a/docs/beyond/concepts/proxy-reflect.mdx
+++ b/docs/beyond/concepts/proxy-reflect.mdx
@@ -1,7 +1,7 @@
---
-title: "Proxy and Reflect: Intercepting Object Operations in JavaScript"
+title: "Proxy & Reflect in JavaScript"
sidebarTitle: "Proxy & Reflect: Intercepting Object Operations"
-description: "Learn JavaScript Proxy and Reflect APIs. Understand how to intercept object operations, create reactive systems, implement validation, and build powerful metaprogramming patterns."
+description: "Learn JavaScript Proxy and Reflect APIs. Intercept object operations, create reactive systems, and build powerful metaprogramming patterns."
---
What if you could intercept every property access on an object? What if reading `user.name` could trigger a function, or setting `user.age = -5` could throw an error automatically?
diff --git a/docs/beyond/concepts/requestanimationframe.mdx b/docs/beyond/concepts/requestanimationframe.mdx
index fe9e3a6d..35ae62ad 100644
--- a/docs/beyond/concepts/requestanimationframe.mdx
+++ b/docs/beyond/concepts/requestanimationframe.mdx
@@ -1,5 +1,5 @@
---
-title: "requestAnimationFrame: Smooth Animations in JavaScript"
+title: "requestAnimationFrame Guide"
sidebarTitle: "requestAnimationFrame: Smooth Animations"
description: "Learn requestAnimationFrame in JavaScript for smooth 60fps animations. Understand how it syncs with browser repaint cycles, delta time, and animation loops."
---
diff --git a/docs/beyond/concepts/resize-observer.mdx b/docs/beyond/concepts/resize-observer.mdx
index 56b221e5..cccabb9d 100644
--- a/docs/beyond/concepts/resize-observer.mdx
+++ b/docs/beyond/concepts/resize-observer.mdx
@@ -1,5 +1,5 @@
---
-title: "ResizeObserver: Detect Element Size Changes in JavaScript"
+title: "ResizeObserver in JavaScript"
sidebarTitle: "ResizeObserver"
description: "Learn the ResizeObserver API in JavaScript. Detect element size changes, build responsive components, and replace inefficient window resize listeners."
---
diff --git a/docs/beyond/concepts/strict-mode.mdx b/docs/beyond/concepts/strict-mode.mdx
index 6b202eed..048b06b2 100644
--- a/docs/beyond/concepts/strict-mode.mdx
+++ b/docs/beyond/concepts/strict-mode.mdx
@@ -1,5 +1,5 @@
---
-title: "Strict Mode: How to Catch Common Mistakes in JavaScript"
+title: "JavaScript Strict Mode"
sidebarTitle: "Strict Mode: Catching Common Mistakes"
description: "Learn JavaScript strict mode and how 'use strict' catches common mistakes. Understand silent errors it prevents, how this changes, and when to use it."
---
diff --git a/docs/beyond/concepts/tagged-template-literals.mdx b/docs/beyond/concepts/tagged-template-literals.mdx
index 4c12ac9c..83a7bf44 100644
--- a/docs/beyond/concepts/tagged-template-literals.mdx
+++ b/docs/beyond/concepts/tagged-template-literals.mdx
@@ -1,7 +1,7 @@
---
-title: "Tagged Template Literals: Custom String Processing in JavaScript"
+title: "Tagged Template Literals"
sidebarTitle: "Tagged Template Literals"
-description: "Learn JavaScript tagged template literals. Understand how tag functions work, access raw strings, build HTML sanitizers, create DSLs, and use String.raw for file paths."
+description: "Learn JavaScript tagged template literals. Understand tag functions, access raw strings, and build HTML sanitizers and DSLs."
---
How do libraries like GraphQL and Lit HTML let you write special syntax inside JavaScript template literals? How can a function intercept and transform template strings before they become a final value?
diff --git a/docs/beyond/concepts/temporal-dead-zone.mdx b/docs/beyond/concepts/temporal-dead-zone.mdx
index 40e4362f..d2765295 100644
--- a/docs/beyond/concepts/temporal-dead-zone.mdx
+++ b/docs/beyond/concepts/temporal-dead-zone.mdx
@@ -1,5 +1,5 @@
---
-title: "Temporal Dead Zone: Variable Initialization in JavaScript"
+title: "Temporal Dead Zone in JS"
sidebarTitle: "Temporal Dead Zone"
description: "Learn the Temporal Dead Zone (TDZ) in JavaScript. Understand why let, const, and class throw ReferenceError before initialization, and how TDZ differs from var."
---
diff --git a/docs/beyond/concepts/typed-arrays-arraybuffers.mdx b/docs/beyond/concepts/typed-arrays-arraybuffers.mdx
index 87f89606..d5417fba 100644
--- a/docs/beyond/concepts/typed-arrays-arraybuffers.mdx
+++ b/docs/beyond/concepts/typed-arrays-arraybuffers.mdx
@@ -1,7 +1,7 @@
---
-title: "Typed Arrays: Working with Binary Data in JavaScript"
+title: "Typed Arrays in JavaScript"
sidebarTitle: "Typed Arrays & ArrayBuffers"
-description: "Learn JavaScript Typed Arrays and ArrayBuffers. Understand binary data handling, DataView, working with WebGL, file processing, and network protocol implementation."
+description: "Learn JavaScript Typed Arrays and ArrayBuffers for binary data handling. Work with DataView, WebGL, and file processing."
---
How do you process a PNG image pixel by pixel? How do you read binary data from a WebSocket? How does WebGL render millions of triangles efficiently?
diff --git a/docs/beyond/concepts/weakmap-weakset.mdx b/docs/beyond/concepts/weakmap-weakset.mdx
index 3f157b52..0ea71bf3 100644
--- a/docs/beyond/concepts/weakmap-weakset.mdx
+++ b/docs/beyond/concepts/weakmap-weakset.mdx
@@ -1,5 +1,5 @@
---
-title: "WeakMap & WeakSet: Weak References in JavaScript"
+title: "WeakMap & WeakSet in JavaScript"
sidebarTitle: "WeakMap & WeakSet"
description: "Learn JavaScript WeakMap and WeakSet. Understand weak references, automatic garbage collection, private data patterns, and when to use them over Map and Set."
---
diff --git a/docs/beyond/getting-started/overview.mdx b/docs/beyond/getting-started/overview.mdx
index 35b2e88e..bcbef876 100644
--- a/docs/beyond/getting-started/overview.mdx
+++ b/docs/beyond/getting-started/overview.mdx
@@ -1,7 +1,7 @@
---
title: "Beyond 33: Extended JavaScript Concepts"
sidebarTitle: "Overview"
-description: "Go deeper into JavaScript with 29 advanced concepts that build on the original 33. Master topics like hoisting, proxies, observers, and performance optimization."
+description: "Go beyond the original 33 with 29 advanced JavaScript concepts. Master hoisting, proxies, observers, and performance optimization."
---
You've learned the fundamentals. Now it's time to go deeper.
diff --git a/docs/concepts/equality-operators.mdx b/docs/concepts/equality-operators.mdx
index db8b9369..56b7f2d2 100644
--- a/docs/concepts/equality-operators.mdx
+++ b/docs/concepts/equality-operators.mdx
@@ -1529,8 +1529,8 @@ Try to answer each question before revealing the solution:
Understanding JavaScript's fundamental data types
-
- How primitives and objects are stored differently in memory
+
+ How primitives and objects behave differently in JavaScript
Understanding where variables are accessible in your code
diff --git a/docs/concepts/javascript-engines.mdx b/docs/concepts/javascript-engines.mdx
index cd75edf7..33924c28 100644
--- a/docs/concepts/javascript-engines.mdx
+++ b/docs/concepts/javascript-engines.mdx
@@ -879,7 +879,7 @@ distance(new Point(0, 0), new Point(3, 4)) // All Points, same shape
How V8 represents and optimizes different value types
-
+
How the engine stores primitives vs objects in memory
diff --git a/docs/concepts/object-creation-prototypes.mdx b/docs/concepts/object-creation-prototypes.mdx
index ff525b11..33c821a2 100644
--- a/docs/concepts/object-creation-prototypes.mdx
+++ b/docs/concepts/object-creation-prototypes.mdx
@@ -33,7 +33,7 @@ The answer is the **[prototype chain](https://developer.mozilla.org/en-US/docs/W
-**Prerequisites:** This guide assumes you understand [Primitive Types](/concepts/primitive-types) and [Value vs Reference Types](/concepts/value-reference-types). If objects and their properties are new to you, read those guides first!
+**Prerequisites:** This guide assumes you understand [Primitive Types](/concepts/primitive-types) and [Primitives vs Objects](/concepts/primitives-objects). If objects and their properties are new to you, read those guides first!
---
@@ -1066,7 +1066,7 @@ function Player(name) {
Explore advanced inheritance patterns and polymorphism in JavaScript
-
+
Understand the difference between primitives and objects, key background for prototypes
diff --git a/docs/concepts/primitive-types.mdx b/docs/concepts/primitive-types.mdx
index 7ace5d0b..90508499 100644
--- a/docs/concepts/primitive-types.mdx
+++ b/docs/concepts/primitive-types.mdx
@@ -1012,8 +1012,8 @@ JavaScript has some famous "weird parts" that every developer should know. Most
## Related Concepts
-
- How primitives and objects are stored differently in memory
+
+ How primitives and objects behave differently in JavaScript
How JavaScript converts between types automatically
diff --git a/docs/concepts/primitives-objects.mdx b/docs/concepts/primitives-objects.mdx
new file mode 100644
index 00000000..c7d01024
--- /dev/null
+++ b/docs/concepts/primitives-objects.mdx
@@ -0,0 +1,977 @@
+---
+title: "Primitives vs Objects: How JavaScript Values Actually Work"
+sidebarTitle: "Primitives vs Objects: How Values Work"
+description: "Learn how JavaScript primitives and objects differ in behavior. Understand immutability, call-by-sharing semantics, why mutation works but reassignment doesn't, and how V8 actually stores values."
+---
+
+Have you ever wondered why changing one variable unexpectedly changes another? Why does this happen?
+
+```javascript
+const original = { name: "Alice" };
+const copy = original;
+copy.name = "Bob";
+
+console.log(original.name); // "Bob" — Wait, what?!
+```
+
+The answer lies in how JavaScript **values behave** — not where they're stored. **Primitives** are immutable and behave independently, while **objects** are mutable and can be shared between variables.
+
+
+**Myth vs Reality:** You may have heard that "primitives are stored on the stack" and "objects are stored on the heap," or that "primitives are passed by value" while "objects are passed by reference." These are simplifications that are technically incorrect. In this guide, we'll learn how JavaScript actually works.
+
+
+
+**What you'll learn in this guide:**
+- The real difference between primitives and objects (it's about mutability, not storage)
+- Why JavaScript uses "call by sharing" — not "pass by value" or "pass by reference"
+- Why mutation works through function parameters but reassignment doesn't
+- Why `{} === {}` returns `false` (object identity)
+- How to properly clone objects (shallow vs deep copy)
+- Common bugs caused by shared references
+- **Bonus:** How V8 actually stores values in memory (the technical truth)
+
+
+
+**Prerequisite:** This guide assumes you understand [Primitive Types](/concepts/primitive-types). If you're not familiar with the 7 primitive types in JavaScript, read that guide first!
+
+
+---
+
+## A Note on Terminology
+
+Before we dive in, let's clear up some widespread misconceptions that even experienced developers get wrong.
+
+
+**Myth vs Reality**
+
+| Common Myth | The Reality |
+|-------------|-------------|
+| "Value types" vs "reference types" | ECMAScript only defines **primitives** and **objects** |
+| "Primitives are stored on the stack" | Implementation-specific — not in the spec |
+| "Objects are stored on the heap" | Implementation-specific — not in the spec |
+| "Primitives are passed by value" | JavaScript uses **call by sharing** for ALL values |
+| "Objects are passed by reference" | Objects are passed by sharing (you can't reassign the original) |
+
+
+### What ECMAScript Actually Says
+
+The [ECMAScript specification](https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values) (the official JavaScript standard) defines exactly two categories of values:
+
+| ECMAScript Term | What It Includes |
+|-----------------|------------------|
+| **Primitive values** | string, number, bigint, boolean, undefined, null, symbol |
+| **Objects** | Everything else (plain objects, arrays, functions, dates, maps, sets, etc.) |
+
+That's it. The spec never mentions "value types," "reference types," "stack," or "heap." These are implementation details that vary by JavaScript engine.
+
+### The Real Distinction: Mutability
+
+The fundamental difference between primitives and objects is **mutability**:
+
+- **Primitives are immutable** — you cannot change a primitive value, only replace it
+- **Objects are mutable** — you CAN change an object's contents
+
+This distinction explains ALL the behavioral differences you'll encounter.
+
+---
+
+## How Primitives and Objects Behave
+
+### Primitives: Immutable and Independent
+
+The 7 primitive types behave as if each variable has its own independent copy:
+
+| Type | Example | Key Behavior |
+|------|---------|--------------|
+| `string` | `"hello"` | Immutable — methods return NEW strings |
+| `number` | `42` | Immutable — arithmetic creates NEW numbers |
+| `bigint` | `9007199254740993n` | Immutable — operations create NEW BigInts |
+| `boolean` | `true` | Immutable |
+| `undefined` | `undefined` | Immutable |
+| `null` | `null` | Immutable |
+| [`symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) | `Symbol("id")` | Immutable AND has identity |
+
+**Key characteristics:**
+- **Immutable** — you can't change them, only replace them
+- **Behave independently** — copies don't affect each other
+- **Compared by value** — same value = equal (except Symbols)
+
+
+**Why immutability matters:** When you write `str.toUpperCase()`, you get a NEW string. The original `str` is unchanged. This is true for ALL string methods — they never mutate the original string.
+
+
+```javascript
+let greeting = "hello";
+let shout = greeting.toUpperCase();
+
+console.log(greeting); // "hello" — unchanged!
+console.log(shout); // "HELLO" — new string
+```
+
+### Objects: Mutable and Shared
+
+Everything that's not a primitive is an object:
+
+| Type | Example | Key Behavior |
+|------|---------|--------------|
+| Object | `{ name: "Alice" }` | Mutable — properties can change |
+| Array | `[1, 2, 3]` | Mutable — elements can change |
+| Function | `function() {}` | Mutable (has properties) |
+| [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) | `new Date()` | Mutable |
+| [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) | `new Map()` | Mutable |
+| [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) | `new Set()` | Mutable |
+
+**Key characteristics:**
+- **Mutable** — you CAN change their contents
+- **Shared by default** — assignment copies the reference, not the object
+- **Compared by identity** — same object = equal (not same contents!)
+
+---
+
+## The House Key Analogy
+
+Think of objects like houses and variables like keys to those houses:
+
+**Primitives (like writing a note):** You write "42" on a sticky note and give a copy to your friend. You each have independent notes. If they change theirs to "100", your note still says "42".
+
+**Objects (like sharing house keys):** Instead of giving your friend the house itself, you give them a copy of your house key. You both have keys to the SAME house. If they rearrange the furniture, you'll see it too — because it's the same house!
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ PRIMITIVES vs OBJECTS: THE KEY ANALOGY │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ PRIMITIVES (Independent Notes) OBJECTS (Keys to Same House) │
+│ │
+│ ┌─────────────┐ ┌─────────────┐ │
+│ │ a = "42" │ │ x = 🔑 ─────────────┐ │
+│ └─────────────┘ └─────────────┘ │ │
+│ ▼ │
+│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │
+│ │ b = "42" │ (separate copy) │ y = 🔑 ─────────►│ 🏠 │ │
+│ └─────────────┘ └─────────────┘ │ {name} │ │
+│ └──────────┘ │
+│ Change b to "100"? Change the house via y? │
+│ a stays "42"! x sees the change too! │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+The key insight: **it's not about where the key is stored, it's about what it points to.**
+
+---
+
+## Call by Sharing: How JavaScript Passes Arguments
+
+Here's where most tutorials get it wrong. JavaScript doesn't use "pass by value" OR "pass by reference." It uses a third strategy called **[call by sharing](https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing)** (also known as "call by object sharing").
+
+
+**Call by sharing** was first described by Barbara Liskov for the CLU programming language in 1974. JavaScript, Python, Ruby, and Java all use this evaluation strategy.
+
+
+### What is Call by Sharing?
+
+When you pass an argument to a function, JavaScript:
+1. Creates a **copy of the reference** (the "key" to the object)
+2. The function parameter gets this copied reference
+3. Both the original variable AND the parameter point to the SAME object
+
+### The Golden Rule
+
+| Operation | Does it affect the original? |
+|-----------|------------------------------|
+| **Mutating properties** (`obj.name = "Bob"`) | ✅ Yes — same object |
+| **Reassigning the parameter** (`obj = newValue`) | ❌ No — only rebinds locally |
+
+### Mutation Works
+
+When you modify an object through a function parameter, the original object is affected:
+
+```javascript
+function rename(person) {
+ person.name = "Bob"; // Mutates the ORIGINAL object
+}
+
+const user = { name: "Alice" };
+rename(user);
+
+console.log(user.name); // "Bob" — changed!
+```
+
+**What happens in memory:**
+
+```
+BEFORE rename(user): INSIDE rename(user):
+
+┌────────────┐ ┌────────────┐
+│user = 🔑 ──┼──► { name: │user = 🔑 ──┼──► { name: "Bob" }
+└────────────┘ "Alice" } ├────────────┤ ▲
+ │person= 🔑 ─┼───────┘
+ └────────────┘ (same house!)
+```
+
+### Reassignment Doesn't Work
+
+If you reassign the parameter to a new object, it only changes the local variable:
+
+```javascript
+function replace(person) {
+ person = { name: "Charlie" }; // Creates NEW local reference
+}
+
+const user = { name: "Alice" };
+replace(user);
+
+console.log(user.name); // "Alice" — unchanged!
+```
+
+**What happens in memory:**
+
+```
+INSIDE replace(user):
+
+┌────────────┐ ┌─────────────────┐
+│user = 🔑 ──┼───►│ { name: "Alice" }│ ← Original, unchanged
+├────────────┤ └─────────────────┘
+│person= 🔑 ─┼───►┌───────────────────┐
+└────────────┘ │ { name: "Charlie" }│ ← New object, local only
+ └───────────────────┘
+```
+
+
+**Why this matters:** If JavaScript used true "pass by reference" (like C++ references), reassigning the parameter WOULD change the original. It doesn't in JavaScript — that's how you know it's "call by sharing," not "pass by reference."
+
+
+### This Applies to Primitives Too!
+
+Here's the mind-bending part: **primitives are also passed by sharing**. You just can't observe it because primitives are immutable — there's no way to mutate them through the parameter.
+
+```javascript
+function double(num) {
+ num = num * 2; // Reassigns the LOCAL variable
+ return num;
+}
+
+let x = 10;
+let result = double(x);
+
+console.log(x); // 10 — unchanged (reassignment doesn't affect original)
+console.log(result); // 20 — returned value
+```
+
+The same "reassignment doesn't work" rule applies to primitives. It's just that with primitives, there's no mutation to try anyway!
+
+---
+
+## Copying Behavior: The Critical Difference
+
+This is where bugs love to hide.
+
+### Copying Primitives: Independent Copies
+
+When you copy a primitive, they behave as completely independent values:
+
+```javascript
+let a = 10;
+let b = a; // b gets an independent copy
+
+b = 20; // changing b has NO effect on a
+
+console.log(a); // 10 (unchanged!)
+console.log(b); // 20
+```
+
+### Copying Objects: Shared References
+
+When you copy an object variable, you copy the *reference*. Both variables now point to the SAME object:
+
+```javascript
+let obj1 = { name: "Alice" };
+let obj2 = obj1; // obj2 gets a copy of the REFERENCE
+
+obj2.name = "Bob"; // modifies the SAME object!
+
+console.log(obj1.name); // "Bob" (changed!)
+console.log(obj2.name); // "Bob"
+```
+
+### The Array Gotcha
+
+Arrays are objects too, so they behave the same way:
+
+```javascript
+let arr1 = [1, 2, 3];
+let arr2 = arr1; // arr2 points to the SAME array
+
+arr2.push(4); // modifies the shared array
+
+console.log(arr1); // [1, 2, 3, 4] — Wait, what?!
+console.log(arr2); // [1, 2, 3, 4]
+```
+
+
+**This trips up EVERYONE at first!** When you write `let arr2 = arr1`, you're NOT creating a new array. You're creating a second variable that points to the same array. Any changes through either variable affect both.
+
+
+---
+
+## Comparison Behavior
+
+### Primitives: Compared by Value
+
+Two primitives are equal if they have the same value:
+
+```javascript
+let a = "hello";
+let b = "hello";
+console.log(a === b); // true — same value
+
+let x = 42;
+let y = 42;
+console.log(x === y); // true — same value
+```
+
+### Objects: Compared by Identity
+
+Two objects are equal only if they are the SAME object (same reference):
+
+```javascript
+let obj1 = { name: "Alice" };
+let obj2 = { name: "Alice" };
+console.log(obj1 === obj2); // false — different objects!
+
+let obj3 = obj1;
+console.log(obj1 === obj3); // true — same reference
+```
+
+### The Empty Object/Array Trap
+
+```javascript
+console.log({} === {}); // false — two different empty objects
+console.log([] === []); // false — two different empty arrays
+console.log([1,2] === [1,2]); // false — two different arrays
+```
+
+
+**How to compare objects/arrays by content:**
+
+```javascript
+// Simple (but limited) approach
+JSON.stringify(obj1) === JSON.stringify(obj2)
+
+// For arrays of primitives
+arr1.length === arr2.length && arr1.every((v, i) => v === arr2[i])
+
+// For complex cases, use a library like Lodash
+_.isEqual(obj1, obj2)
+```
+
+**Caution with JSON.stringify:** Property order matters! `{a:1, b:2}` and `{b:2, a:1}` produce different strings. It also fails with `undefined`, functions, Symbols, circular references, `NaN`, and `Infinity`.
+
+
+### Symbols: The Exception
+
+[Symbols](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) are primitives but have **identity** — two symbols with the same description are NOT equal:
+
+```javascript
+const sym1 = Symbol("id");
+const sym2 = Symbol("id");
+
+console.log(sym1 === sym2); // false — different symbols!
+console.log(sym1 === sym1); // true — same symbol
+```
+
+---
+
+## Mutation vs Reassignment
+
+Understanding this distinction is crucial for avoiding bugs.
+
+### Mutation: Changing the Contents
+
+Mutation modifies the existing object in place:
+
+```javascript
+const arr = [1, 2, 3];
+
+// These are all MUTATIONS:
+arr.push(4); // [1, 2, 3, 4]
+arr[0] = 99; // [99, 2, 3, 4]
+arr.pop(); // [99, 2, 3]
+arr.sort(); // modifies in place
+
+const obj = { name: "Alice" };
+
+// These are all MUTATIONS:
+obj.name = "Bob"; // changes property
+obj.age = 25; // adds property
+delete obj.age; // removes property
+```
+
+### Reassignment: Pointing to a New Value
+
+Reassignment makes the variable point to something else entirely:
+
+```javascript
+let arr = [1, 2, 3];
+arr = [4, 5, 6]; // REASSIGNMENT — new array
+
+let obj = { name: "Alice" };
+obj = { name: "Bob" }; // REASSIGNMENT — new object
+```
+
+### The `const` Trap
+
+`const` prevents **reassignment** but NOT **mutation**:
+
+```javascript
+const arr = [1, 2, 3];
+
+// ✅ Mutations are ALLOWED:
+arr.push(4); // works!
+arr[0] = 99; // works!
+
+// ❌ Reassignment is BLOCKED:
+arr = [4, 5, 6]; // TypeError: Assignment to constant variable
+
+const obj = { name: "Alice" };
+
+// ✅ Mutations are ALLOWED:
+obj.name = "Bob"; // works!
+obj.age = 25; // works!
+
+// ❌ Reassignment is BLOCKED:
+obj = { name: "Eve" }; // TypeError: Assignment to constant variable
+```
+
+
+**Common misconception:** Many developers think `const` creates an "immutable" variable. It doesn't! It only prevents reassignment. The contents of objects and arrays declared with `const` can still be changed.
+
+
+---
+
+## True Immutability with [`Object.freeze()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)
+
+If you need a truly immutable object, use `Object.freeze()`:
+
+```javascript
+const user = Object.freeze({ name: "Alice", age: 25 });
+
+user.name = "Bob"; // Silently fails (or throws in strict mode)
+user.email = "a@b.com"; // Can't add properties
+delete user.age; // Can't delete properties
+
+console.log(user); // { name: "Alice", age: 25 } — unchanged!
+```
+
+
+**Object.freeze() is shallow!** It only freezes the top level. Nested objects can still be modified:
+
+```javascript
+const user = Object.freeze({
+ name: "Alice",
+ address: { city: "NYC" }
+});
+
+user.name = "Bob"; // Blocked
+user.address.city = "LA"; // Works! Nested object not frozen
+
+console.log(user.address.city); // "LA"
+```
+
+
+For deep freezing, you need a recursive function or use `structuredClone()` to create a deep copy first.
+
+---
+
+## Shallow Copy vs Deep Copy
+
+When you need a truly independent copy of an object, you have two options.
+
+### Shallow Copy: One Level Deep
+
+A shallow copy creates a new object with copies of the top-level properties. But nested objects are still shared!
+
+```javascript
+const original = {
+ name: "Alice",
+ address: { city: "NYC" }
+};
+
+// Shallow copy methods:
+const copy1 = { ...original }; // Spread operator
+const copy2 = Object.assign({}, original); // Object.assign
+
+// Top-level changes are independent:
+copy1.name = "Bob";
+console.log(original.name); // "Alice" ✅
+
+// But nested objects are SHARED:
+copy1.address.city = "LA";
+console.log(original.address.city); // "LA" 😱
+```
+
+### Deep Copy: All Levels
+
+A deep copy creates completely independent copies at every level.
+
+```javascript
+const original = {
+ name: "Alice",
+ scores: [95, 87, 92],
+ address: { city: "NYC" }
+};
+
+// structuredClone() — the modern way (ES2022+)
+const deep = structuredClone(original);
+
+// Now everything is independent:
+deep.address.city = "LA";
+console.log(original.address.city); // "NYC" ✅
+
+deep.scores.push(100);
+console.log(original.scores); // [95, 87, 92] ✅
+```
+
+
+**Which to use:**
+- **[`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone)** — Use this for most cases (modern browsers)
+- **`JSON.parse(JSON.stringify())`** — Only for simple objects (loses functions, Dates, undefined)
+- **Lodash `_.cloneDeep()`** — When you need maximum compatibility
+
+
+---
+
+## How Engines Actually Store Values
+
+
+**Why this section exists:** Many tutorials teach that "primitives go on the stack, objects go on the heap." This is a simplification that's often wrong. Here's what actually happens.
+
+
+### The ECMAScript Specification Doesn't Define Storage
+
+The ECMAScript specification defines **behavior**, not **implementation**. It never mentions "stack" or "heap." Different JavaScript engines can store values however they want, as long as the behavior matches the spec.
+
+### How V8 Actually Works
+
+V8 (Chrome, Node.js, Deno) uses a technique called **pointer tagging** to efficiently represent values.
+
+#### Smis (Small Integers): The Only "Direct" Values
+
+The ONLY values V8 stores "directly" (not on the heap) are **Smis** — Small Integers in the range approximately -2³¹ to 2³¹-1 (about -2 billion to 2 billion).
+
+```
+┌─────────────────────────────────────────────────────────────────────────┐
+│ V8 POINTER TAGGING │
+├─────────────────────────────────────────────────────────────────────────┤
+│ │
+│ Smi (Small Integer): │
+│ ┌────────────────────────────────────────────────────────────┬─────┐ │
+│ │ Integer Value (31 bits) │ 0 │ │
+│ └────────────────────────────────────────────────────────────┴─────┘ │
+│ Tag bit │
+│ │
+│ Heap Pointer (everything else): │
+│ ┌────────────────────────────────────────────────────────────┬─────┐ │
+│ │ Memory Address │ 1 │ │
+│ └────────────────────────────────────────────────────────────┴─────┘ │
+│ Tag bit │
+│ │
+└─────────────────────────────────────────────────────────────────────────┘
+```
+
+#### Everything Else Lives on the Heap
+
+This includes values you might think are "simple":
+
+| Value Type | Where It's Stored | Why |
+|------------|-------------------|-----|
+| Small integers (-2³¹ to 2³¹-1) | Directly (as Smi) | Fixed size, fits in pointer |
+| Large numbers | Heap (HeapNumber) | Needs 64-bit float |
+| **Strings** | **Heap** | **Dynamically sized** |
+| **BigInts** | **Heap** | **Arbitrary precision** |
+| Objects, Arrays | Heap | Complex structures |
+
+
+**The big misconception:** Strings are NOT fixed-size values stored on the stack. A string like `"hello"` and a string with a million characters are both stored on the heap. The variable just holds a pointer to that heap location.
+
+
+### String Interning
+
+V8 optimizes identical strings by potentially sharing memory (string interning). Two variables with the value `"hello"` might point to the same memory location internally. But this is an optimization — strings still *behave* as independent values because they're immutable.
+
+### Why the Stack/Heap Model is Taught
+
+The simplified stack/heap model is useful for understanding **behavioral differences**:
+- Things that "behave like stack values" = act independently
+- Things that "behave like heap values" = can be shared
+
+Just know it's a **mental model for behavior**, not how JavaScript actually works internally.
+
+
+**Want to go deeper?** Check out our [JavaScript Engines](/concepts/javascript-engines) guide for more on V8 internals, JIT compilation, and optimization.
+
+
+---
+
+## Common Bugs and Pitfalls
+
+
+
+ ```javascript
+ // BUG: Modifying function parameter
+ function processUsers(users) {
+ users.push({ name: "New User" }); // Mutates original!
+ return users;
+ }
+
+ const myUsers = [{ name: "Alice" }];
+ processUsers(myUsers);
+ console.log(myUsers); // [{ name: "Alice" }, { name: "New User" }]
+
+ // FIX: Create a copy first
+ function processUsers(users) {
+ const copy = [...users];
+ copy.push({ name: "New User" });
+ return copy;
+ }
+ ```
+
+
+
+ ```javascript
+ // These MUTATE the original array:
+ arr.push() arr.pop()
+ arr.shift() arr.unshift()
+ arr.splice() arr.sort()
+ arr.reverse() arr.fill()
+
+ // These RETURN a new array (safe):
+ arr.map() arr.filter()
+ arr.slice() arr.concat()
+ arr.flat() arr.flatMap()
+ arr.toSorted() arr.toReversed() // ES2023
+ arr.toSpliced() // ES2023
+
+ // GOTCHA: sort() mutates!
+ const nums = [3, 1, 2];
+ const sorted = nums.sort(); // nums is NOW [1, 2, 3]!
+
+ // FIX: Copy first, or use toSorted()
+ const sorted = [...nums].sort();
+ const sorted = nums.toSorted(); // ES2023
+ ```
+
+
+
+ ```javascript
+ // BUG: This will NEVER work
+ if (user1 === user2) { } // Compares identity
+ if (arr1 === arr2) { } // Compares identity
+
+ // Even these fail:
+ [] === [] // false
+ {} === {} // false
+ [1, 2] === [1, 2] // false
+
+ // FIX: Compare contents
+ JSON.stringify(a) === JSON.stringify(b) // Simple but limited
+
+ // Or use a deep equality function/library
+ ```
+
+
+
+ ```javascript
+ // BUG: Shallow copy doesn't clone nested objects
+ const user = {
+ name: "Alice",
+ settings: { theme: "dark" }
+ };
+
+ const copy = { ...user };
+ copy.settings.theme = "light";
+
+ console.log(user.settings.theme); // "light" — Original changed!
+
+ // FIX: Use deep copy
+ const copy = structuredClone(user);
+ ```
+
+
+
+ ```javascript
+ // BUG: Thinking you have two arrays
+ const original = [1, 2, 3];
+ const backup = original; // NOT a backup!
+
+ original.push(4);
+ console.log(backup); // [1, 2, 3, 4] — "backup" changed!
+
+ // FIX: Actually copy the array
+ const backup = [...original];
+ const backup = original.slice();
+ ```
+
+
+
+ ```javascript
+ // BUG: Thinking reassignment passes through
+ function clearArray(arr) {
+ arr = []; // Only reassigns local variable!
+ }
+
+ const myArr = [1, 2, 3];
+ clearArray(myArr);
+ console.log(myArr); // [1, 2, 3] — unchanged!
+
+ // FIX: Mutate instead of reassign
+ function clearArray(arr) {
+ arr.length = 0; // Mutates the original
+ }
+ ```
+
+
+
+---
+
+## Best Practices
+
+
+**Guidelines for working with objects:**
+
+1. **Treat objects as immutable when possible**
+ ```javascript
+ // Instead of mutating:
+ user.name = "Bob";
+
+ // Create a new object:
+ const updatedUser = { ...user, name: "Bob" };
+ ```
+
+2. **Use `const` by default** — prevents accidental reassignment
+
+3. **Know which methods mutate**
+ - Mutating: `push`, `pop`, `sort`, `reverse`, `splice`
+ - Non-mutating: `map`, `filter`, `slice`, `concat`, `toSorted`
+
+4. **Use `structuredClone()` for deep copies**
+ ```javascript
+ const clone = structuredClone(original);
+ ```
+
+5. **Clone function parameters if you need to modify them**
+ ```javascript
+ function processData(data) {
+ const copy = structuredClone(data);
+ // Now safe to modify copy
+ }
+ ```
+
+6. **Be explicit about intent** — comment when mutating on purpose
+
+
+---
+
+## Key Takeaways
+
+
+**The key things to remember:**
+
+1. **Primitives vs Objects** — the ECMAScript terms (not "value types" vs "reference types")
+
+2. **The real difference is mutability** — primitives are immutable, objects are mutable
+
+3. **Call by sharing** — JavaScript passes ALL values as copies of references; mutation works, reassignment doesn't
+
+4. **Object identity** — objects are compared by identity, not content (`{} === {}` is false)
+
+5. **`const` prevents reassignment, not mutation** — use `Object.freeze()` for true immutability
+
+6. **Shallow copy shares nested objects** — use `structuredClone()` for deep copies
+
+7. **Know your array methods** — `push/pop/sort` mutate; `map/filter/slice` don't
+
+8. **The stack/heap model is a simplification** — useful for understanding behavior, not technically accurate
+
+9. **In V8, only Smis are stored directly** — strings, BigInts, and objects all live on the heap
+
+10. **Symbols have identity** — two `Symbol("id")` are different, unlike other primitives
+
+
+---
+
+## Test Your Knowledge
+
+
+
+ **Answer:**
+
+ - **Primitives are immutable** — you cannot change a primitive value, only replace it. Copies behave independently.
+
+ - **Objects are mutable** — you CAN change an object's contents. Multiple variables can point to the same object.
+
+ The distinction is about **mutability**, not storage location.
+
+
+
+ ```javascript
+ let a = { count: 1 };
+ let b = a;
+ b.count = 5;
+ console.log(a.count);
+ ```
+
+ **Answer:** `5`
+
+ Both `a` and `b` point to the same object. When you modify `b.count`, you're modifying the shared object, which `a` also sees. This is because **mutation affects the shared object**.
+
+
+
+ **Answer:** Because `===` compares **identity** (same object), not contents.
+
+ Each `{}` creates a NEW empty object in memory. Even though they have the same contents (both empty), they are different objects.
+
+ ```javascript
+ {} === {} // false (different objects)
+
+ const a = {};
+ const b = a;
+ a === b // true (same object)
+ ```
+
+
+
+ **Answer:**
+
+ - **Call by sharing:** Function receives a copy of the reference. Mutation works, but reassignment only changes the local parameter.
+
+ - **Pass by reference (C++ style):** Parameter is an alias for the argument. Reassignment WOULD change the original.
+
+ JavaScript uses call by sharing. That's why this doesn't work:
+
+ ```javascript
+ function replace(obj) {
+ obj = { new: "object" }; // Only changes local parameter
+ }
+
+ let x = { old: "object" };
+ replace(x);
+ console.log(x); // { old: "object" } — unchanged!
+ ```
+
+
+
+ **Answer:** No!
+
+ `const` only prevents **reassignment** — you can't make the variable point to a different value. But you CAN still **mutate** the object's contents.
+
+ ```javascript
+ const obj = { name: "Alice" };
+
+ obj.name = "Bob"; // ✅ Allowed (mutation)
+ obj.age = 25; // ✅ Allowed (mutation)
+ obj = {}; // ❌ Error (reassignment)
+ ```
+
+ Use `Object.freeze()` for true immutability.
+
+
+
+ **Answer:** No! This is a common myth.
+
+ In V8, **only Smis (small integers)** are stored directly. Strings are dynamically-sized and stored on the heap. The variable holds a pointer to the string's location in heap memory.
+
+ The "stack vs heap" model is a **mental model for behavior**, not how JavaScript actually works.
+
+
+
+ **Answer:**
+
+ - **Shallow copy** creates a new object but shares nested objects
+ - **Deep copy** creates independent copies at ALL levels
+
+ ```javascript
+ const original = { nested: { value: 1 } };
+
+ // Shallow: nested is shared
+ const shallow = { ...original };
+ shallow.nested.value = 2;
+ console.log(original.nested.value); // 2 (affected!)
+
+ // Deep: completely independent
+ const deep = structuredClone(original);
+ deep.nested.value = 3;
+ console.log(original.nested.value); // 2 (unchanged)
+ ```
+
+
+
+---
+
+## Related Concepts
+
+
+
+ Deep dive into the 7 primitive types and their characteristics
+
+
+ How V8 compiles and optimizes your code, including memory management
+
+
+ How JavaScript converts between types automatically
+
+
+ How closures capture references to variables
+
+
+
+---
+
+## Reference
+
+
+
+ The official specification defining primitive values and objects in JavaScript.
+
+
+ MDN's comprehensive guide to JavaScript's type system and data structures.
+
+
+ Documentation on freezing objects for immutability.
+
+
+ The modern way to create deep copies of objects.
+
+
+
+## Articles
+
+
+
+ The definitive explanation of call-by-sharing in ECMAScript by a language theory expert. Includes comparison with true pass-by-reference and detailed examples.
+
+
+ Excellent deep-dive debunking the "pass by reference" myth. Explains true references vs object references with C++ comparisons.
+
+
+ Beginner-friendly guide focusing on the practical differences between mutable and immutable data in JavaScript.
+
+
+ Clear explanation with visual diagrams showing how primitives and objects behave differently.
+
+
+
+## Videos
+
+
+
+ Modern explanation using the correct "call by sharing" terminology. Part of an excellent Understanding JavaScript series.
+
+
+ Popular tutorial (37K+ views) with clear examples of how primitives and objects behave differently in functions.
+
+
+ Comprehensive walkthrough covering primitives vs objects, function parameters, and common misconceptions.
+
+
diff --git a/docs/concepts/pure-functions.mdx b/docs/concepts/pure-functions.mdx
index 0d00a1e9..8c143e03 100644
--- a/docs/concepts/pure-functions.mdx
+++ b/docs/concepts/pure-functions.mdx
@@ -31,7 +31,7 @@ A pure function is simple, predictable, and trustworthy. Once you understand why
-**Helpful background:** This guide references object and array mutations frequently. If you're not comfortable with how JavaScript handles [value vs reference types](/concepts/value-reference-types), read that guide first. It explains why `const arr = [1,2,3]; arr.push(4)` works but shouldn't surprise you.
+**Helpful background:** This guide references object and array mutations frequently. If you're not comfortable with how JavaScript handles [primitives vs objects](/concepts/primitives-objects), read that guide first. It explains why `const arr = [1,2,3]; arr.push(4)` works but shouldn't surprise you.
---
@@ -337,7 +337,7 @@ console.log(user.address.city) // 'NYC' — Original safe!
-**The Trap:** Spread operator (`...`) only copies one level deep. If you have nested objects or arrays, mutations to the nested data will affect the original. Use `structuredClone()` for deep copies, or see our [Value vs Reference Types](/concepts/value-reference-types) guide for more patterns.
+**The Trap:** Spread operator (`...`) only copies one level deep. If you have nested objects or arrays, mutations to the nested data will affect the original. Use `structuredClone()` for deep copies, or see our [Primitives vs Objects](/concepts/primitives-objects) guide for more patterns.
---
@@ -744,7 +744,7 @@ The pure functions (`formatUsername`, `isValidUsername`) are easy to test and re
## Related Concepts
-
+
Understanding mutations, shallow vs deep copies, and why objects behave differently than primitives
diff --git a/docs/concepts/type-coercion.mdx b/docs/concepts/type-coercion.mdx
index 0e763349..67c81ba9 100644
--- a/docs/concepts/type-coercion.mdx
+++ b/docs/concepts/type-coercion.mdx
@@ -425,7 +425,7 @@ const display = user && user.name;
## Object to Primitive Conversion
-When JavaScript needs to convert an [object to a primitive](/concepts/value-reference-types) (including arrays), it follows a specific algorithm.
+When JavaScript needs to convert an [object to a primitive](/concepts/primitives-objects) (including arrays), it follows a specific algorithm.
### The ToPrimitive Algorithm
@@ -961,7 +961,7 @@ function process(count) {
Understanding the basic data types that coercion converts between
-
+
How primitives and objects behave differently during coercion
diff --git a/docs/concepts/value-reference-types.mdx b/docs/concepts/value-reference-types.mdx
deleted file mode 100644
index b899a36a..00000000
--- a/docs/concepts/value-reference-types.mdx
+++ /dev/null
@@ -1,1288 +0,0 @@
----
-title: "Value vs Reference Types"
-sidebarTitle: "Value vs Reference Types: How Memory Works"
-description: "Learn value vs reference types in JavaScript. Understand how primitives and objects are stored in memory and avoid mutation bugs."
----
-
-Have you ever wondered why changing one variable unexpectedly changes another? Why does this happen?
-
-```javascript
-const original = { name: "Alice" };
-const copy = original;
-copy.name = "Bob";
-
-console.log(original.name); // "Bob" — Wait, what?!
-```
-
-The answer lies in how JavaScript stores data in memory. **Primitives** (like numbers and strings) store actual values, while **objects** store *references* (pointers) to data. This difference causes countless bugs in JavaScript code.
-
-
-**What you'll learn in this guide:**
-- How JavaScript stores primitives vs objects in memory
-- Why copying an object doesn't create a new object
-- The difference between "pass by value" and "pass by reference"
-- Why `{} === {}` returns `false`
-- How to properly clone objects (shallow vs deep copy)
-- Common bugs caused by reference sharing
-
-
-
-**Prerequisite:** This guide assumes you understand [Primitive Types](/concepts/primitive-types). If you're not familiar with the 7 primitive types in JavaScript, read that guide first!
-
-
----
-
-## What Are Value Types and Reference Types?
-
-JavaScript has two categories of data types that behave very differently:
-
-### Value Types (Primitives)
-
-**The 7 primitive types** store their values directly:
-
-| Type | Example | Stored As |
-|------|---------|-----------|
-| `string` | `"hello"` | The string value |
-| `number` | `42` | The numeric value |
-| `bigint` | `9007199254740993n` | The large integer value |
-| `boolean` | `true` | The boolean value |
-| `undefined` | `undefined` | The undefined value |
-| `null` | `null` | The null value |
-| [`symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) | `Symbol("id")` | The unique symbol |
-
-**Key characteristics:**
-- Behave as if stored directly in the variable
-- Immutable — you can't change them, only replace them
-- Copied by value — copies are independent
-- Compared by value — same value = equal
-
-
-**Under the hood:** Modern JavaScript engines optimize string storage through a technique called "string interning" — identical strings may share the same memory location internally. However, this is an optimization detail; strings still *behave* as independent values when you work with them.
-
-
-### Reference Types
-
-**Everything else** is a reference type:
-
-| Type | Example | Stored As |
-|------|---------|-----------|
-| Object | `{ name: "Alice" }` | Reference to object |
-| Array | `[1, 2, 3]` | Reference to array |
-| Function | `function() {}` | Reference to function |
-| Date | `new Date()` | Reference to date |
-| RegExp | `/pattern/` | Reference to regex |
-| [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) | `new Map()` | Reference to map |
-| [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) | `new Set()` | Reference to set |
-
-**Key characteristics:**
-- Variable stores a *reference* (pointer) to the actual data
-- Mutable — you CAN change their contents
-- Copied by reference — copies point to the SAME object
-- Compared by reference — same reference = equal (not same contents!)
-
----
-
-## The Sticky Note vs The Map: A Real-World Analogy
-
-Imagine you have two ways to share information with a friend:
-
-**Sticky Note (Value Types):** You write "42" on a sticky note and hand it to your friend. They now have their own note with "42" on it. If they change their note to "100", your note still says "42". You each have independent copies.
-
-**Map to Treasure (Reference Types):** Instead of giving your friend the treasure itself, you give them a map to where the treasure is buried. Now you BOTH have maps pointing to the SAME treasure. If they dig it up and add more gold, you'll see the extra gold too, because you're both looking at the same treasure!
-
-```
-┌─────────────────────────────────────────────────────────────────────────┐
-│ VALUE TYPES vs REFERENCE TYPES │
-├─────────────────────────────────────────────────────────────────────────┤
-│ │
-│ VALUE TYPE (Sticky Note) REFERENCE TYPE (Map to Treasure) │
-│ │
-│ ┌─────────────┐ ┌─────────────┐ │
-│ │ x = 42 │ │ x = ────────────────┐ │
-│ └─────────────┘ └─────────────┘ │ │
-│ ▼ │
-│ ┌─────────────┐ ┌─────────────┐ ┌──────────┐ │
-│ │ y = 42 │ (independent copy) │ y = ────────────►│ {...} │ │
-│ └─────────────┘ └─────────────┘ └──────────┘ │
-│ │
-│ Change y? Change the object via y? │
-│ x stays the same! x sees the change too! │
-│ │
-└─────────────────────────────────────────────────────────────────────────┘
-```
-
-This difference between "storing the value itself" vs "storing a map to the value" is fundamental to understanding JavaScript.
-
-
-**Quick Rule:** Primitives store the actual value. Copying creates an independent copy. Objects and arrays store a *reference* (pointer). Copying creates another pointer to the SAME data.
-
-
----
-
-## How Memory Works: Stack vs Heap
-
-To truly understand the difference, you need to know where JavaScript stores data.
-
-
-**Important note:** The stack/heap model described below is a **conceptual simplification** to help you understand how value types and reference types *behave*. The JavaScript specification doesn't define where values are stored in memory—actual engines (V8, SpiderMonkey, etc.) may optimize storage differently. What matters is understanding the *behavior* difference, not the physical memory location.
-
-
-### The Stack: Home of Primitives
-
-The **stack** is a fast, organized region of memory. It stores:
-- Primitive values
-- References (pointers) to objects
-- Function call information
-
-```
-┌─────────────────────────────────────────────────────────────────────────┐
-│ THE STACK │
-├─────────────────────────────────────────────────────────────────────────┤
-│ │
-│ ┌────────────────────────────┐ │
-│ │ name = "Alice" │ ← Actual string value │
-│ ├────────────────────────────┤ │
-│ │ age = 25 │ ← Actual number value │
-│ ├────────────────────────────┤ │
-│ │ isActive = true │ ← Actual boolean value │
-│ ├────────────────────────────┤ │
-│ │ user = 0x7F3A ──────┼──── Points to heap │
-│ └────────────────────────────┘ │
-│ │
-│ Fixed size, fast access │
-│ │
-└─────────────────────────────────────────────────────────────────────────┘
-```
-
-### The Heap: Home of Objects
-
-The **heap** is a larger, less organized region for dynamic data:
-- Objects
-- Arrays
-- Functions
-- Anything that can grow or change size
-
-```
-┌─────────────────────────────────────────────────────────────────────────┐
-│ THE HEAP │
-├─────────────────────────────────────────────────────────────────────────┤
-│ │
-│ ┌─────────────────────────────────────┐ │
-│ │ 0x7F3A: │ │
-│ │ { │ │
-│ │ name: "Alice", │ │
-│ │ age: 25, │ │
-│ │ hobbies: ["reading", "gaming"] │ │
-│ │ } │ │
-│ └─────────────────────────────────────┘ │
-│ │
-│ ┌─────────────────────────────────────┐ │
-│ │ 0x8B2C: │ │
-│ │ [1, 2, 3, 4, 5] │ │
-│ └─────────────────────────────────────┘ │
-│ │
-│ Dynamic size, slower access │
-│ │
-└─────────────────────────────────────────────────────────────────────────┘
-```
-
-### Putting It All Together
-
-When you create variables, here's what happens:
-
-```javascript
-let name = "Alice"; // String stored on stack
-let age = 25; // Number stored on stack
-let user = { name: "Alice" }; // Reference on stack, object on heap
-let scores = [95, 87, 92]; // Reference on stack, array on heap
-```
-
-```
-┌─────────────────────────────────────────────────────────────────────────┐
-│ STACK AND HEAP TOGETHER │
-├─────────────────────────────────────────────────────────────────────────┤
-│ │
-│ STACK HEAP │
-│ ┌─────────────────────┐ ┌────────────────────────────┐ │
-│ │ name = "Alice" │ │ │ │
-│ ├─────────────────────┤ │ ┌──────────────────────┐ │ │
-│ │ age = 25 │ │ │ { name: "Alice" } │ │ │
-│ ├─────────────────────┤ │ └──────────────────────┘ │ │
-│ │ user = 0x001 ─────┼───────────┼──────────▲ │ │
-│ ├─────────────────────┤ │ │ │
-│ │ scores = 0x002 ─────┼───────────┼───┐ ┌──────────────────┐ │ │
-│ └─────────────────────┘ │ └─►│ [95, 87, 92] │ │ │
-│ │ └──────────────────┘ │ │
-│ └────────────────────────────┘ │
-│ │
-└─────────────────────────────────────────────────────────────────────────┘
-```
-
----
-
-## Copying Behavior: The Critical Difference
-
-This is where things get interesting, and where bugs love to hide.
-
-### Copying Primitives: Independent Copies
-
-When you copy a primitive, you get a completely independent value:
-
-```javascript
-let a = 10;
-let b = a; // b gets a COPY of the value 10
-
-b = 20; // changing b has NO effect on a
-
-console.log(a); // 10 (unchanged!)
-console.log(b); // 20
-```
-
-**What happens in memory:**
-
-```
-STEP 1: let a = 10 STEP 2: let b = a STEP 3: b = 20
-
-┌──────────────┐ ┌──────────────┐ ┌──────────────┐
-│ a = 10 │ │ a = 10 │ │ a = 10 │
-└──────────────┘ ├──────────────┤ ├──────────────┤
- │ b = 10 │ (copy!) │ b = 20 │
- └──────────────┘ └──────────────┘
-
- Two independent Changing b
- copies of 10 doesn't touch a
-```
-
-### Copying Objects: Shared References
-
-When you copy an object, you copy the *reference*. Both variables now point to the SAME object:
-
-```javascript
-let obj1 = { name: "Alice" };
-let obj2 = obj1; // obj2 gets a COPY of the REFERENCE
-
-obj2.name = "Bob"; // modifies the SAME object!
-
-console.log(obj1.name); // "Bob" (changed!)
-console.log(obj2.name); // "Bob"
-```
-
-**What happens in memory:**
-
-```
-STEP 1: Create obj1 STEP 2: let obj2 = obj1
-
-STACK HEAP STACK HEAP
-┌────────────┐ ┌──────────────────┐ ┌────────────┐ ┌──────────────────┐
-│obj1 = 0x01─┼─►│ { name: "Alice" }│ │obj1 = 0x01─┼──►│ { name: "Alice" }│
-└────────────┘ └──────────────────┘ ├────────────┤ │ │
- │obj2 = 0x01─┼──► (same object!) │
- └────────────┘ └──────────────────┘
-
-STEP 3: obj2.name = "Bob"
-
-STACK HEAP
-┌────────────┐ ┌──────────────────┐
-│obj1 = 0x01─┼──►│ { name: "Bob" } │ ← Both see this change!
-├────────────┤ │ │
-│obj2 = 0x01─┼──► (same object!) │
-└────────────┘ └──────────────────┘
-```
-
-### The Array Surprise
-
-Arrays are objects too, so they behave the same way:
-
-```javascript
-let arr1 = [1, 2, 3];
-let arr2 = arr1; // arr2 points to the SAME array
-
-arr2.push(4); // modifies the shared array
-
-console.log(arr1); // [1, 2, 3, 4] — Wait, what?!
-console.log(arr2); // [1, 2, 3, 4]
-```
-
-
-**This catches EVERYONE at first!** When you write `let arr2 = arr1`, you're NOT creating a new array. You're creating a second variable that points to the same array. Any changes through either variable affect both.
-
-
----
-
-## Comparison Behavior
-
-### Primitives: Compared by Value
-
-Two primitives are equal if they have the same value:
-
-```javascript
-let a = "hello";
-let b = "hello";
-console.log(a === b); // true — same value
-
-let x = 42;
-let y = 42;
-console.log(x === y); // true — same value
-```
-
-### Objects: Compared by Reference
-
-Two objects are equal only if they are the SAME object (same reference):
-
-```javascript
-let obj1 = { name: "Alice" };
-let obj2 = { name: "Alice" };
-console.log(obj1 === obj2); // false — different objects!
-
-let obj3 = obj1;
-console.log(obj1 === obj3); // true — same reference
-```
-
-**Visual explanation:**
-
-```
-obj1 and obj2: Different objects, same contents
-
-STACK HEAP
-┌────────────┐ ┌──────────────────┐
-│obj1 = 0x01─┼─►│ { name: "Alice" }│ ← Object A
-├────────────┤ └──────────────────┘
-│obj2 = 0x02─┼─►┌──────────────────┐
-└────────────┘ │ { name: "Alice" }│ ← Object B (different!)
- └──────────────────┘
-
-obj1 === obj2? 0x01 === 0x02? FALSE!
-```
-
-```
-obj1 and obj3: Same object
-
-STACK HEAP
-┌────────────┐ ┌──────────────────┐
-│obj1 = 0x01─┼──►│ { name: "Alice" }│
-├────────────┤ │ │
-│obj3 = 0x01─┼──► (same object!) │
-└────────────┘ └──────────────────┘
-
-obj1 === obj3? 0x01 === 0x01? TRUE!
-```
-
-### The Empty Object/Array Trap
-
-```javascript
-console.log({} === {}); // false — two different empty objects
-console.log([] === []); // false — two different empty arrays
-console.log([1,2] === [1,2]); // false — two different arrays
-```
-
-
-**How to compare objects/arrays by content:**
-
-```javascript
-// Simple (but limited) approach
-JSON.stringify(obj1) === JSON.stringify(obj2)
-
-// For arrays of primitives
-arr1.length === arr2.length && arr1.every((v, i) => v === arr2[i])
-
-// For complex cases, use a library like Lodash
-_.isEqual(obj1, obj2)
-```
-
-**Caution with JSON.stringify:** Property order matters! `{a:1, b:2}` and `{b:2, a:1}` will produce different strings even though they're logically equal. It also fails with `undefined`, functions, Symbols, circular references, `NaN`, and `Infinity`. For reliable deep equality, use a library like Lodash's `_.isEqual()`.
-
-
----
-
-## Functions and Parameters
-
-Here's a topic that confuses even experienced developers:
-
-**JavaScript is ALWAYS "pass by value"**, but when passing objects, the *value being passed is a reference*.
-
-### Passing Primitives
-
-When you pass a primitive to a function, the function receives a copy:
-
-```javascript
-function double(num) {
- num = num * 2; // changes the LOCAL copy only
- return num;
-}
-
-let x = 10;
-let result = double(x);
-
-console.log(x); // 10 (unchanged!)
-console.log(result); // 20
-```
-
-**What happens:**
-
-```
-BEFORE double(x): INSIDE double(x): AFTER double(x):
-
-┌──────────────┐ ┌──────────────┐ ┌──────────────┐
-│ x = 10 │ │ x = 10 │ │ x = 10 │
-└──────────────┘ ├──────────────┤ └──────────────┘
- │ num = 10 │ (copy)
- └──────────────┘
- ↓
- ┌──────────────┐
- │ num = 20 │ (modified copy)
- └──────────────┘
-```
-
-### Passing Objects: Mutation WORKS
-
-When you pass an object, the function receives a copy of the reference. Both point to the same object:
-
-```javascript
-function rename(person) {
- person.name = "Bob"; // mutates the ORIGINAL object!
-}
-
-let user = { name: "Alice" };
-rename(user);
-
-console.log(user.name); // "Bob" — changed!
-```
-
-**What happens:**
-
-```
-BEFORE rename(user): INSIDE rename(user):
-
-STACK HEAP STACK HEAP
-┌────────────┐ ┌────────────┐
-│user = 0x01─┼─►{ name: │user = 0x01─┼──►{ name: "Bob" }
-└────────────┘ "Alice" } ├────────────┤ ▲
- │person=0x01─┼───────┘
- └────────────┘ (same object!)
-```
-
-### Passing Objects: Reassignment DOESN'T Work
-
-But if you reassign the parameter, you're only changing the local copy of the reference:
-
-```javascript
-function replace(person) {
- person = { name: "Charlie" }; // creates NEW local object
-}
-
-let user = { name: "Alice" };
-replace(user);
-
-console.log(user.name); // "Alice" — unchanged!
-```
-
-**What happens:**
-
-```
-INSIDE replace(user):
-
-STACK HEAP
-┌────────────┐ ┌─────────────────┐
-│user = 0x01─┼─►│ { name: "Alice" }│ ← Original, unchanged
-├────────────┤ └─────────────────┘
-│person=0x02─┼─►┌──────────────────┐
-└────────────┘ │ { name: "Charlie" }│ ← New object, discarded
- └──────────────────┘
-```
-
-
-**The key insight:** You can *mutate* an object through a function parameter, but you cannot *replace* the original object. Reassigning the parameter only changes where that local variable points.
-
-
----
-
-## Mutation vs Reassignment
-
-Understanding this distinction is crucial for avoiding bugs.
-
-### Mutation: Changing the Contents
-
-Mutation modifies the existing object in place:
-
-```javascript
-const arr = [1, 2, 3];
-
-// These are all MUTATIONS:
-arr.push(4); // [1, 2, 3, 4]
-arr[0] = 99; // [99, 2, 3, 4]
-arr.pop(); // [99, 2, 3]
-arr.sort(); // modifies in place
-
-const obj = { name: "Alice" };
-
-// These are all MUTATIONS:
-obj.name = "Bob"; // changes property
-obj.age = 25; // adds property
-delete obj.age; // removes property
-```
-
-### Reassignment: Pointing to a New Value
-
-Reassignment makes the variable point to something else entirely:
-
-```javascript
-let arr = [1, 2, 3];
-arr = [4, 5, 6]; // REASSIGNMENT — new array
-
-let obj = { name: "Alice" };
-obj = { name: "Bob" }; // REASSIGNMENT — new object
-```
-
-### The `const` Trap
-
-`const` prevents **reassignment** but NOT **mutation**:
-
-```javascript
-const arr = [1, 2, 3];
-
-// ✅ Mutations are ALLOWED:
-arr.push(4); // works!
-arr[0] = 99; // works!
-
-// ❌ Reassignment is BLOCKED:
-arr = [4, 5, 6]; // TypeError: Assignment to constant variable
-
-const obj = { name: "Alice" };
-
-// ✅ Mutations are ALLOWED:
-obj.name = "Bob"; // works!
-obj.age = 25; // works!
-
-// ❌ Reassignment is BLOCKED:
-obj = { name: "Eve" }; // TypeError: Assignment to constant variable
-```
-
-
-**Common misconception:** Many developers think `const` creates an "immutable" variable. It doesn't! It only prevents reassignment. The contents of objects and arrays declared with `const` can still be changed.
-
-
----
-
-## True Immutability with [`Object.freeze()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)
-
-We learned that `const` doesn't make objects immutable. It only prevents reassignment. But what if you NEED a truly immutable object?
-
-### Object.freeze(): Shallow Immutability
-
-`Object.freeze()` prevents any changes to an object's properties:
-
-```javascript
-const user = Object.freeze({ name: "Alice", age: 25 });
-
-user.name = "Bob"; // Silently fails (or throws in strict mode)
-user.email = "a@b.com"; // Can't add properties
-delete user.age; // Can't delete properties
-
-console.log(user); // { name: "Alice", age: 25 } — unchanged!
-```
-
-**What Object.freeze() prevents:**
-- Changing existing property values
-- Adding new properties
-- Deleting properties
-- Changing property descriptors (like making a property writable)
-
-### Checking If an Object Is Frozen
-
-```javascript
-const frozen = Object.freeze({ a: 1 });
-const normal = { a: 1 };
-
-console.log(Object.isFrozen(frozen)); // true
-console.log(Object.isFrozen(normal)); // false
-```
-
-
-**Object.freeze() is shallow!** It only freezes the top level. Nested objects can still be modified:
-
-```javascript
-const user = Object.freeze({
- name: "Alice",
- address: { city: "NYC" }
-});
-
-user.name = "Bob"; // Blocked
-user.address.city = "LA"; // Works! Nested object not frozen
-
-console.log(user.address.city); // "LA"
-```
-
-
-### Deep Freeze: Making Everything Immutable
-
-To freeze nested objects too, you need a recursive "deep freeze" function:
-
-```javascript
-function deepFreeze(obj, seen = new WeakSet()) {
- // Prevent infinite loops from circular references
- if (seen.has(obj)) return obj;
- seen.add(obj);
-
- // Get all property names (including symbols)
- const propNames = Reflect.ownKeys(obj);
-
- // Freeze nested objects first
- for (const name of propNames) {
- const value = obj[name];
- if (value && typeof value === "object") {
- deepFreeze(value, seen);
- }
- }
-
- // Then freeze the object itself
- return Object.freeze(obj);
-}
-
-const user = deepFreeze({
- name: "Alice",
- address: { city: "NYC" }
-});
-
-user.address.city = "LA"; // Now this is blocked too!
-console.log(user.address.city); // "NYC"
-```
-
-
-**Why the `seen` WeakSet?** Objects can have circular references (e.g., `obj.self = obj`). Without tracking visited objects, the function would recurse infinitely. The WeakSet ensures each object is only processed once.
-
-
-### Related Methods: freeze vs seal vs preventExtensions
-
-| Method | Add Properties | Delete Properties | Change Values |
-|--------|:-------------:|:-----------------:|:-------------:|
-| `Object.freeze()` | No | No | No |
-| `Object.seal()` | No | No | **Yes** |
-| `Object.preventExtensions()` | No | **Yes** | **Yes** |
-
-```javascript
-// Object.seal() — can change values, but can't add/delete
-const sealed = Object.seal({ name: "Alice" });
-sealed.name = "Bob"; // Works!
-sealed.age = 25; // Fails — can't add
-delete sealed.name; // Fails — can't delete
-
-// Object.preventExtensions() — can change/delete, but can't add
-const noExtend = Object.preventExtensions({ name: "Alice" });
-noExtend.name = "Bob"; // Works!
-delete noExtend.name; // Works!
-noExtend.age = 25; // Fails — can't add
-```
-
-
-**When to use Object.freeze():**
-- Configuration objects that should never change
-- Constants or enums in your application
-- Protecting objects passed to untrusted code
-- Debugging mutation bugs (freeze the object and see what breaks!)
-
-
----
-
-## Shallow Copy vs Deep Copy
-
-When you need a truly independent copy of an object, you have two options.
-
-### Shallow Copy: One Level Deep
-
-A shallow copy creates a new object with copies of the top-level properties. But nested objects are still shared!
-
-**Shallow copy methods:**
-
-```javascript
-const original = {
- name: "Alice",
- scores: [95, 87, 92],
- address: { city: "NYC" }
-};
-
-// Method 1: Spread operator
-const copy1 = { ...original };
-
-// Method 2: Object.assign
-const copy2 = Object.assign({}, original);
-
-// For arrays:
-const arrCopy1 = [...originalArray];
-const arrCopy2 = originalArray.slice();
-const arrCopy3 = Array.from(originalArray);
-```
-
-**The problem with shallow copy:**
-
-```javascript
-const original = {
- name: "Alice",
- address: { city: "NYC" }
-};
-
-const shallow = { ...original };
-
-// Top-level changes are independent:
-shallow.name = "Bob";
-console.log(original.name); // "Alice" ✅
-
-// But nested objects are SHARED:
-shallow.address.city = "LA";
-console.log(original.address.city); // "LA" 😱
-```
-
-**Visual explanation:**
-
-```
-SHALLOW COPY
-
-original shallow
-┌─────────────────┐ ┌─────────────────┐
-│ name: "Alice" │ │ name: "Alice" │ (independent copy)
-│ address: 0x01 ──┼────┐ │ address: 0x01 ──┼────┐
-└─────────────────┘ │ └─────────────────┘ │
- │ │
- ▼ ▼
- ┌─────────────────┐
- │ { city: "NYC" } │ ← SHARED! Both point here
- └─────────────────┘
-```
-
-### Deep Copy: All Levels
-
-A deep copy creates completely independent copies at every level.
-
-**Method 1: [`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) (Recommended)**
-
-```javascript
-const original = {
- name: "Alice",
- scores: [95, 87, 92],
- address: { city: "NYC" },
- date: new Date()
-};
-
-const deep = structuredClone(original);
-
-// Now everything is independent:
-deep.address.city = "LA";
-console.log(original.address.city); // "NYC" ✅
-
-deep.scores.push(100);
-console.log(original.scores); // [95, 87, 92] ✅
-```
-
-**Method 2: JSON trick (has limitations)**
-
-```javascript
-const deep = JSON.parse(JSON.stringify(original));
-```
-
-### Comparing the Methods
-
-
-
- **Pros:**
- - Handles most types correctly
- - Preserves Dates, Maps, Sets, ArrayBuffers
- - Handles circular references
- - Built into JavaScript (ES2022+)
-
- **Cons:**
- - Cannot clone functions
- - Cannot clone DOM nodes
- - Cannot clone property descriptors, getters/setters
- - Cannot clone the prototype chain
- - Symbol-keyed properties are ignored
- - Error objects lose their stack trace (only `message` is preserved)
- - Not available in older browsers (pre-2022)
-
- ```javascript
- const obj = {
- date: new Date(),
- set: new Set([1, 2, 3]),
- map: new Map([["key", "value"]])
- };
-
- const clone = structuredClone(obj);
- // Works perfectly! ✅
- ```
-
-
- **Pros:**
- - Works in all browsers
- - Simple to use
-
- **Cons:**
- - **Loses functions** — they disappear
- - **Loses undefined** — properties with undefined are removed
- - **Converts Dates to strings** — not Date objects
- - **Cannot handle circular references** — throws error
- - **Loses Symbol keys** — they're ignored
- - **Loses Map/Set** — converted to empty objects
-
- ```javascript
- const obj = {
- fn: () => {}, // ❌ lost
- date: new Date(), // ❌ becomes string
- undef: undefined, // ❌ property removed
- set: new Set([1, 2]) // ❌ becomes {}
- };
-
- const clone = JSON.parse(JSON.stringify(obj));
- // { date: "2025-12-29T..." } — Most data lost!
- ```
-
-
-
-
-**Which to use:**
-- **`structuredClone()`** — Use this for most cases (modern browsers)
-- **JSON trick** — Only for simple objects with no functions, dates, or special types
-- **Lodash `_.cloneDeep()`** — When you need maximum compatibility
-
-
----
-
-## Common Bugs and Pitfalls
-
-
-
- ```javascript
- // BUG: Modifying function parameter
- function processUsers(users) {
- users.push({ name: "New User" }); // Mutates original!
- return users;
- }
-
- const myUsers = [{ name: "Alice" }];
- processUsers(myUsers);
- console.log(myUsers); // [{ name: "Alice" }, { name: "New User" }]
-
- // FIX: Create a copy first
- function processUsers(users) {
- const copy = [...users];
- copy.push({ name: "New User" });
- return copy;
- }
- ```
-
-
-
- ```javascript
- // These MUTATE the original array:
- arr.push() arr.pop()
- arr.shift() arr.unshift()
- arr.splice() arr.sort()
- arr.reverse() arr.fill()
-
- // These RETURN a new array (safe):
- arr.map() arr.filter()
- arr.slice() arr.concat()
- arr.flat() arr.flatMap()
- arr.toSorted() arr.toReversed() // ES2023
- arr.toSpliced() // ES2023
-
- // GOTCHA: sort() mutates!
- const nums = [3, 1, 2];
- const sorted = nums.sort(); // nums is NOW [1, 2, 3]!
-
- // FIX: Copy first, or use toSorted()
- const sorted = [...nums].sort();
- const sorted = nums.toSorted(); // ES2023
- ```
-
-
-
- ```javascript
- // BUG: This will NEVER work
- if (user1 === user2) { } // Compares references
- if (arr1 === arr2) { } // Compares references
- if (config === defaultConfig) { } // Compares references
-
- // Even these fail:
- [] === [] // false
- {} === {} // false
- [1, 2] === [1, 2] // false
-
- // FIX: Compare contents
- JSON.stringify(a) === JSON.stringify(b) // Simple but limited
-
- // Or use a deep equality function
- function deepEqual(a, b) {
- return JSON.stringify(a) === JSON.stringify(b);
- }
- ```
-
-
-
- ```javascript
- // BUG: Shallow copy doesn't clone nested objects
- const user = {
- name: "Alice",
- settings: { theme: "dark" }
- };
-
- const copy = { ...user };
- copy.settings.theme = "light";
-
- console.log(user.settings.theme); // "light" — Original changed!
-
- // FIX: Use deep copy
- const copy = structuredClone(user);
- ```
-
-
-
- ```javascript
- // BUG: Default object gets mutated across calls
- function addItem(item, list = []) {
- list.push(item);
- return list;
- }
-
- // This works fine with primitives, but with objects...
- // Actually, this specific case is fine because default
- // parameters are evaluated fresh each call.
-
- // But THIS is a problem:
- const defaultList = [];
- function addItem(item, list = defaultList) {
- list.push(item);
- return list;
- }
-
- addItem("a"); // ["a"]
- addItem("b"); // ["a", "b"] — defaultList was mutated!
- ```
-
-
-
- ```javascript
- // BUG: Thinking you have two arrays
- const original = [1, 2, 3];
- const backup = original; // NOT a backup!
-
- original.push(4);
- console.log(backup); // [1, 2, 3, 4] — "backup" changed!
-
- // FIX: Actually copy the array
- const backup = [...original];
- const backup = original.slice();
- ```
-
-
-
- When you store objects in Maps or arrays, those references prevent garbage collection, even if you don't need the object anymore.
-
- ```javascript
- // Potential memory leak: cache holds references forever
- const cache = new Map();
-
- function processUser(user) {
- cache.set(user.id, user); // user can never be garbage collected
- }
-
- // Even if user objects are no longer needed elsewhere,
- // the cache keeps them alive in memory
- ```
-
- **Solutions:**
-
- - **[WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)** — Keys are "weakly held" and can be garbage collected
- - **Manual cleanup** — Delete entries when done
-
- ```javascript
- // WeakMap: objects can be garbage collected when no other references exist
- const cache = new WeakMap();
-
- function processUser(user) {
- cache.set(user, computeExpensiveData(user));
- }
- // When 'user' object is no longer referenced elsewhere,
- // it AND its cached data can be garbage collected
- ```
-
-
- **WeakMap vs Map:** WeakMap keys must be objects (not primitives), and you can't iterate over a WeakMap. Use it when you want cached data to automatically disappear when the source object is gone.
-
-
-
-
----
-
-## Best Practices
-
-
-**Guidelines for working with reference types:**
-
-1. **Treat objects as immutable when possible**
- ```javascript
- // Instead of mutating:
- user.name = "Bob";
-
- // Create a new object:
- const updatedUser = { ...user, name: "Bob" };
- ```
-
-2. **Use `const` by default** — prevents accidental reassignment
-
-3. **Know which methods mutate**
- - Mutating: `push`, `pop`, `sort`, `reverse`, `splice`
- - Non-mutating: `map`, `filter`, `slice`, `concat`, `toSorted`
-
-4. **Use `structuredClone()` for deep copies**
- ```javascript
- const clone = structuredClone(original);
- ```
-
-5. **Be explicit about intent** — comment when mutating on purpose
- ```javascript
- // Intentionally mutating for performance
- largeArray.sort((a, b) => a - b);
- ```
-
-6. **Clone function parameters if you need to modify them**
- ```javascript
- function processData(data) {
- const copy = structuredClone(data);
- // Now safe to modify copy
- }
- ```
-
-
----
-
-## Key Takeaways
-
-
-**The key things to remember:**
-
-1. **Value types** (primitives) store values directly; **reference types** store pointers
-
-2. **Copying a primitive** creates an independent copy — changing one doesn't affect the other
-
-3. **Copying an object/array** copies the reference — both point to the SAME data
-
-4. **Comparison:** primitives compare by value, objects compare by reference
-
-5. **Functions:** JavaScript passes everything by value, but object values ARE references
-
-6. **Mutation ≠ Reassignment:** `const` only prevents reassignment, not mutation
-
-7. **Shallow copy** (spread, Object.assign) only copies one level — nested objects are shared
-
-8. **Deep copy** with `structuredClone()` creates completely independent copies
-
-9. **Know your array methods:** `push/pop/sort` mutate; `map/filter/slice` don't
-
-10. **True immutability** requires `Object.freeze()` — but it's shallow, so use deep freeze for nested objects
-
-
----
-
-## Test Your Knowledge
-
-
-
- **Answer:**
-
- - **Value types (primitives)** store the actual value directly. Copying creates an independent copy, and comparison checks if values are the same.
-
- - **Reference types (objects, arrays, functions)** store a pointer/reference to the data. Copying creates another pointer to the SAME data, and comparison checks if both point to the same object.
-
-
-
- ```javascript
- let a = { count: 1 };
- let b = a;
- b.count = 5;
- console.log(a.count);
- ```
-
- **Answer:** `5`
-
- Both `a` and `b` point to the same object. When you modify `b.count`, you're modifying the shared object, which `a` also sees.
-
-
-
- **Answer:** Because `===` compares references, not contents.
-
- Each `{}` creates a NEW empty object in memory with a different reference. Even though they have the same contents (both empty), they are different objects at different memory addresses.
-
- ```javascript
- {} === {} // false (different objects)
-
- const a = {};
- const b = a;
- a === b // true (same reference)
- ```
-
-
-
- **Answer:**
-
- - **Shallow copy** creates a new object and copies top-level properties. Nested objects are NOT copied — they're still shared references.
-
- - **Deep copy** creates a completely independent copy at ALL levels. Nested objects are also cloned.
-
- ```javascript
- const original = { nested: { value: 1 } };
-
- // Shallow: nested is shared
- const shallow = { ...original };
- shallow.nested.value = 2;
- console.log(original.nested.value); // 2 (affected!)
-
- // Deep: completely independent
- const deep = structuredClone(original);
- deep.nested.value = 3;
- console.log(original.nested.value); // 2 (unchanged)
- ```
-
-
-
- **Answer:** No!
-
- `const` only prevents **reassignment** — you can't make the variable point to a different value. But you CAN still **mutate** the object's contents.
-
- ```javascript
- const obj = { name: "Alice" };
-
- obj.name = "Bob"; // ✅ Allowed (mutation)
- obj.age = 25; // ✅ Allowed (mutation)
- obj = {}; // ❌ Error (reassignment)
- ```
-
-
-
- **Answer:** The original object IS modified!
-
- When you pass an object to a function, the function receives a copy of the reference. Both the original variable and the function parameter point to the same object. Mutations through either will affect the shared object.
-
- ```javascript
- function addAge(person) {
- person.age = 30; // Mutates the original!
- }
-
- const user = { name: "Alice" };
- addAge(user);
- console.log(user.age); // 30
- ```
-
- However, if you *reassign* the parameter inside the function, it only changes the local variable, not the original.
-
-
-
- **Answer:** No! `Object.freeze()` is shallow.
-
- It only freezes the top-level properties. Nested objects can still be modified:
-
- ```javascript
- const user = Object.freeze({
- name: "Alice",
- address: { city: "NYC" }
- });
-
- user.name = "Bob"; // Blocked (frozen)
- user.address.city = "LA"; // Works! (nested object not frozen)
-
- console.log(user.address.city); // "LA"
- ```
-
- To freeze everything, you need a recursive "deep freeze" function that freezes all nested objects.
-
-
-
- **Answer:** They protect different things:
-
- - **`const`** prevents **reassignment** — you can't make the variable point to a different value
- - **`Object.freeze()`** prevents **mutation** — you can't change the object's properties
-
- ```javascript
- // const alone: can mutate, can't reassign
- const obj1 = { a: 1 };
- obj1.a = 2; // ✅ Works
- obj1 = {}; // ❌ Error
-
- // freeze alone: can reassign (if let), can't mutate
- let obj2 = Object.freeze({ a: 1 });
- obj2.a = 2; // ❌ Fails silently
- obj2 = {}; // ✅ Works (it's let)
-
- // Both together: can't do either
- const obj3 = Object.freeze({ a: 1 });
- obj3.a = 2; // ❌ Fails silently
- obj3 = {}; // ❌ Error
- ```
-
-
-
----
-
-## Related Concepts
-
-
-
- Deep dive into the 7 primitive types and their characteristics
-
-
- How JavaScript converts between types automatically
-
-
- How closures capture references to variables
-
-
- Understanding == vs === and type checking
-
-
-
----
-
-## Reference
-
-
-
- Official documentation on JavaScript's type system, including primitives and objects.
-
-
- Documentation on freezing objects for immutability.
-
-
- The modern way to create deep copies of objects.
-
-
- Maps with weak references that allow garbage collection.
-
-
-
-## Articles
-
-
-
- Clear explanation by Arnav Aggarwal with visual diagrams showing how primitives and objects behave differently in memory.
-
-
- JavaScript Tutorial's guide includes animated diagrams showing stack vs heap memory allocation. Covers copying behavior and function parameter passing with runnable code examples.
-
-
- Miro Koczka explains why `const` doesn't make objects immutable and how to avoid accidental mutations. Includes common bug patterns and fixes.
-
-
- Kyle Simpson's definitive guide to JavaScript's type system. Free to read online.
-
-
-
-## Videos
-
-
-
- Mosh uses whiteboard diagrams to show exactly how primitives live on the stack while objects live on the heap. 10-minute video that makes memory concepts click.
-
-
- Academind's Max demonstrates mutation bugs in real-time, then shows how to fix them with spread operators and structuredClone. Good for seeing the problems before learning solutions.
-
-
- Focused explanation of how function parameters work with primitives vs objects. Great for understanding the "pass by value of the reference" concept.
-
-
diff --git a/docs/docs.json b/docs/docs.json
index c6b0cd2c..8a60f6f1 100644
--- a/docs/docs.json
+++ b/docs/docs.json
@@ -69,7 +69,7 @@
"icon": "cube",
"pages": [
"concepts/primitive-types",
- "concepts/value-reference-types",
+ "concepts/primitives-objects",
"concepts/type-coercion",
"concepts/equality-operators",
"concepts/scope-and-closures",
@@ -258,6 +258,12 @@
}
]
},
+ "redirects": [
+ {
+ "source": "/concepts/value-reference-types",
+ "destination": "/concepts/primitives-objects"
+ }
+ ],
"footer": {
"socials": {
"github": "https://github.com/leonardomso/33-js-concepts",
diff --git a/docs/getting-started/learning-paths.mdx b/docs/getting-started/learning-paths.mdx
index 75d8fc6f..2ef0e285 100644
--- a/docs/getting-started/learning-paths.mdx
+++ b/docs/getting-started/learning-paths.mdx
@@ -43,7 +43,7 @@ If you're new to JavaScript, follow this order. Each concept builds on the previ
Start with the building blocks of JavaScript.
1. [Primitive Types](/concepts/primitive-types) - What types of data exist in JavaScript?
- 2. [Value vs Reference Types](/concepts/value-reference-types) - How is data stored and copied?
+ 2. [Primitives vs Objects](/concepts/primitives-objects) - How do JavaScript values behave differently?
3. [Type Coercion](/concepts/type-coercion) - How JavaScript converts between types
4. [Equality Operators](/concepts/equality-operators) - The difference between == and ===
diff --git a/tests/fundamentals/value-reference-types/value-reference-types.test.js b/tests/fundamentals/primitives-objects/primitives-objects.test.js
similarity index 91%
rename from tests/fundamentals/value-reference-types/value-reference-types.test.js
rename to tests/fundamentals/primitives-objects/primitives-objects.test.js
index 6ab7fc56..f5b9f904 100644
--- a/tests/fundamentals/value-reference-types/value-reference-types.test.js
+++ b/tests/fundamentals/primitives-objects/primitives-objects.test.js
@@ -1,10 +1,22 @@
import { describe, it, expect } from 'vitest'
-describe('Value Types and Reference Types', () => {
- describe('Copying Primitives', () => {
+/**
+ * Tests for Primitives vs Objects concept
+ * Source: /docs/concepts/primitives-objects.mdx
+ *
+ * Key concepts tested:
+ * - Primitives are immutable, objects are mutable
+ * - Call by sharing semantics (mutation works, reassignment doesn't)
+ * - Object identity vs value comparison
+ * - Shallow vs deep copying
+ */
+
+describe('Primitives and Objects', () => {
+ describe('Primitives: Immutable and Independent', () => {
+ // Source: lines 85-100 - Primitives behave independently
it('should create independent copies when copying primitives', () => {
let a = 10
- let b = a // b gets a COPY of the value 10
+ let b = a // b gets an independent copy
b = 20 // changing b has NO effect on a
@@ -12,11 +24,20 @@ describe('Value Types and Reference Types', () => {
expect(b).toBe(20)
})
- it('should demonstrate string variables are independent copies', () => {
+ // Source: lines 101-108 - String immutability
+ it('should demonstrate string immutability - methods return new strings', () => {
+ let greeting = "hello"
+ let shout = greeting.toUpperCase()
+
+ expect(greeting).toBe("hello") // unchanged!
+ expect(shout).toBe("HELLO") // new string
+ })
+
+ it('should demonstrate primitive variables are independent', () => {
let name = "Alice"
let age = 25
- let user = { name: "Alice" } // Reference on stack, object on heap
- let scores = [95, 87, 92] // Reference on stack, array on heap
+ let user = { name: "Alice" } // Object reference
+ let scores = [95, 87, 92] // Array reference
expect(name).toBe("Alice")
expect(age).toBe(25)
@@ -25,28 +46,65 @@ describe('Value Types and Reference Types', () => {
})
})
- describe('Copying Objects', () => {
+ describe('Objects: Mutable and Shared', () => {
it('should share reference when copying objects', () => {
let obj1 = { name: "Alice" }
- let obj2 = obj1 // obj2 gets a COPY of the REFERENCE
+ let obj2 = obj1
- obj2.name = "Bob" // modifies the SAME object!
+ obj2.name = "Bob"
- expect(obj1.name).toBe("Bob") // changed!
+ expect(obj1.name).toBe("Bob")
expect(obj2.name).toBe("Bob")
})
it('should share reference when copying arrays', () => {
let arr1 = [1, 2, 3]
- let arr2 = arr1 // arr2 points to the SAME array
+ let arr2 = arr1
- arr2.push(4) // modifies the shared array
+ arr2.push(4)
- expect(arr1).toEqual([1, 2, 3, 4]) // changed!
+ expect(arr1).toEqual([1, 2, 3, 4])
expect(arr2).toEqual([1, 2, 3, 4])
})
})
+ describe('Call by Sharing Semantics', () => {
+ it('should allow mutation through function parameters', () => {
+ function rename(person) {
+ person.name = "Bob"
+ }
+
+ const user = { name: "Alice" }
+ rename(user)
+
+ expect(user.name).toBe("Bob")
+ })
+
+ it('should NOT allow reassignment through function parameters', () => {
+ function replace(person) {
+ person = { name: "Charlie" }
+ }
+
+ const user = { name: "Alice" }
+ replace(user)
+
+ expect(user.name).toBe("Alice")
+ })
+
+ it('should demonstrate call by sharing applies to primitives too', () => {
+ function double(num) {
+ num = num * 2
+ return num
+ }
+
+ let x = 10
+ let result = double(x)
+
+ expect(x).toBe(10)
+ expect(result).toBe(20)
+ })
+ })
+
describe('Comparison Behavior', () => {
describe('Primitives: Compared by Value', () => {
it('should return true for equal primitive values', () => {