`, but both the button's handler AND the div's handler fire. Why? Or you add a click listener to a parent element, and it somehow catches clicks on all its children. How does that work?
@@ -46,7 +50,7 @@ This happens because of **event bubbling** — one of the three phases every DOM
**Event propagation** is the process by which an event travels through the DOM tree when triggered on an element. Instead of the event only affecting the element you clicked, it travels through the element's ancestors in a specific order, giving each one a chance to respond.
-Every DOM event goes through **three phases**:
+According to the [W3C UI Events specification](https://www.w3.org/TR/uievents/#event-flow), every DOM event goes through **three phases**:
1. **Capturing phase** — The event travels DOWN from `window` to the target element
2. **Target phase** — The event arrives at the element that triggered it
@@ -78,7 +82,7 @@ Every DOM event goes through **three phases**:
└─────────────────────────────────────────────────────────────────────────┘
```
-By default, event listeners fire during the **bubbling phase** (Phase 3). That's why when you click a button, the button's handler fires first, then its parent's handler, then its grandparent's, and so on up to `window`.
+By default, event listeners fire during the **bubbling phase** (Phase 3). [Can I Use data](https://caniuse.com/addeventlistener) confirms that `addEventListener` with capture support is available in all modern browsers since IE9. That's why when you click a button, the button's handler fires first, then its parent's handler, then its grandparent's, and so on up to `window`.
@@ -410,7 +414,7 @@ link.addEventListener('click', (e) => {
## Events That Don't Bubble
-Most events bubble, but some don't. Here are the common ones:
+Most events bubble, but some don't. As [MDN's event reference](https://developer.mozilla.org/en-US/docs/Web/Events) documents, each event specifies whether it bubbles in its specification. Here are the common ones:
| Event | Bubbles? | Bubbling Alternative |
|-------|----------|---------------------|
@@ -675,6 +679,32 @@ form.addEventListener('click', (e) => {
---
+## Frequently Asked Questions
+
+
+
+ Event bubbling is the process where an event triggered on a child element propagates upward through its ancestor elements in the DOM tree. According to the W3C DOM specification, bubbling is Phase 3 of event propagation and is the default phase in which `addEventListener` handlers fire.
+
+
+
+ Bubbling travels from the target element up to `window`, while capturing travels from `window` down to the target. By default, listeners fire during bubbling. To listen during capturing, pass `{ capture: true }` as the third argument to `addEventListener`. MDN documents that most real-world code uses bubbling exclusively.
+
+
+
+ Call `event.stopPropagation()` to prevent the event from reaching other elements while still allowing other handlers on the same element to run. Use `event.stopImmediatePropagation()` to stop all further handling entirely. Use these sparingly — the CSS-Tricks article "Dangers of Stopping Event Propagation" warns they can break analytics and third-party modal libraries.
+
+
+
+ The `focus`, `blur`, `mouseenter`, `mouseleave`, `load`, `unload`, and `scroll` events do not bubble. For delegation with focus events, use `focusin` and `focusout` instead, which are their bubbling equivalents as defined in the W3C UI Events spec.
+
+
+
+ `event.target` is the element that originally triggered the event, while `event.currentTarget` is the element that has the listener attached. They are the same when you click directly on the element with the listener, but differ when events bubble up from child elements.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/event-delegation.mdx b/docs/beyond/concepts/event-delegation.mdx
index b7e59c6d..fb1daeff 100644
--- a/docs/beyond/concepts/event-delegation.mdx
+++ b/docs/beyond/concepts/event-delegation.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Events"
+"article:tag": "event delegation, event bubbling, dynamic elements, memory efficiency, event handling"
---
How do you handle click events on a list that could have 10, 100, or 1,000 items? What about elements that don't even exist yet — dynamically added after the page loads? If you're adding individual event listeners to each element, you're working too hard and using too much memory.
@@ -44,7 +48,7 @@ document.querySelector('.todo-list').addEventListener('click', (event) => {
## What is Event Delegation?
-**Event delegation** is a pattern where you attach a single event listener to a parent element to handle events on its child elements. When an event occurs on a child, it bubbles up to the parent, where the listener catches it and determines which specific child triggered the event. This approach reduces memory usage, simplifies code, and automatically handles dynamically added elements.
+**Event delegation** is a pattern where you attach a single event listener to a parent element to handle events on its child elements. When an event occurs on a child, it bubbles up to the parent, where the listener catches it and determines which specific child triggered the event. As documented by [javascript.info](https://javascript.info/event-delegation), this approach reduces memory usage, simplifies code, and automatically handles dynamically added elements.
Think of event delegation like a receptionist at an office building. Instead of giving every employee their own personal doorbell, visitors ring one doorbell at the reception desk. The receptionist then determines who the visitor wants to see and routes them appropriately. One point of contact handles all visitors efficiently.
@@ -148,7 +152,7 @@ document.querySelector('.container').addEventListener('click', (event) => {
### Element.closest() — Finding Ancestor Elements
-The [`closest()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/closest) method traverses up the DOM tree to find the nearest ancestor (or the element itself) that matches a selector. This is crucial when the actual click target is a nested element:
+The [`closest()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/closest) method traverses up the DOM tree to find the nearest ancestor (or the element itself) that matches a selector. [Can I Use data](https://caniuse.com/element-closest) shows `closest()` is supported in over 96% of browsers globally. This is crucial when the actual click target is a nested element:
```javascript
// Problem: User might click the icon inside the button
@@ -471,7 +475,7 @@ function validateInput(input) {
## Performance Benefits
-Event delegation significantly reduces memory usage when dealing with many elements:
+Event delegation significantly reduces memory usage when dealing with many elements. According to [web.dev performance guidelines](https://web.dev/articles/dom-size-and-interactivity), minimizing the number of event listeners is a key strategy for improving Interaction to Next Paint (INP) scores:
```javascript
// Without delegation: 1000 listeners
@@ -820,6 +824,32 @@ document.querySelector('.my-component').addEventListener('click', (event) => {
---
+## Frequently Asked Questions
+
+
+
+ Event delegation is a technique where you attach a single event listener to a parent element instead of multiple listeners on individual child elements. It works because of event bubbling — when a child is clicked, the event travels up to the parent where your listener catches it. MDN recommends this pattern for handling events on dynamic content.
+
+
+
+ Use delegation when you have many similar elements that need the same handler, when elements are added or removed dynamically, or when memory efficiency matters. According to web.dev, reducing the number of event listeners directly improves page interactivity and INP scores.
+
+
+
+ `matches()` checks if the exact `event.target` matches a CSS selector, while `closest()` traverses up the DOM to find the nearest matching ancestor. Use `closest()` when your clickable elements contain nested children like icons or spans, since `event.target` might be the inner element rather than the button itself.
+
+
+
+ No. Events that don't bubble — such as `focus`, `blur`, `mouseenter`, and `mouseleave` — cannot be delegated using the standard bubbling approach. The W3C UI Events spec defines `focusin` and `focusout` as bubbling alternatives for focus events, or you can use the capture phase as a workaround.
+
+
+
+ Yes — this is one of its biggest advantages. Since the listener is on the parent, any child elements added later are automatically handled without needing to attach new listeners. This makes delegation essential for SPAs and any UI that renders content dynamically.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/garbage-collection.mdx b/docs/beyond/concepts/garbage-collection.mdx
index fc8be733..4bd01701 100644
--- a/docs/beyond/concepts/garbage-collection.mdx
+++ b/docs/beyond/concepts/garbage-collection.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Memory & Performance"
+"article:tag": "garbage collection, mark and sweep, reachability, memory efficiency, gc algorithm"
---
What happens to objects after you stop using them? When you create a variable, assign it an object, and then reassign it to something else, where does that original object go? Does it just sit there forever, taking up space?
@@ -11,7 +15,7 @@ let user = { name: 'Alice', age: 30 }
user = null // What happens to { name: 'Alice', age: 30 }?
```
-The answer is **garbage collection**. JavaScript automatically finds objects you're no longer using and frees the memory they occupy. You don't have to manually allocate or deallocate memory like in C or C++. The JavaScript engine handles it for you, running a background process that cleans up unused objects.
+The answer is **garbage collection**. JavaScript automatically finds objects you're no longer using and frees the memory they occupy. You don't have to manually allocate or deallocate memory like in C or C++. As MDN documents, the JavaScript engine handles it for you, running a background process that cleans up unused objects — a design choice made since the language's creation in 1995.
**What you'll learn in this guide:**
@@ -228,13 +232,13 @@ createCycle()
// With mark-and-sweep: Both collected (unreachable from roots)
```
-Old versions of Internet Explorer (IE6/7) used reference counting for DOM objects, which caused notorious memory leaks when JavaScript objects and DOM elements referenced each other. All modern engines use mark-and-sweep or variations of it.
+Old versions of Internet Explorer (IE6/7) used reference counting for DOM objects, which caused notorious memory leaks when JavaScript objects and DOM elements referenced each other. According to web.dev's guide on fixing memory leaks, all modern engines now use mark-and-sweep or variations of it, eliminating circular reference leaks entirely.
---
## Generational Garbage Collection
-Modern engines like V8 don't just use basic mark-and-sweep. They use **generational garbage collection** based on an important observation: **most objects die young**.
+Modern engines like V8 don't just use basic mark-and-sweep. They use **generational garbage collection** based on an important observation: **most objects die young**. According to the V8 blog, the Orinoco garbage collector processes the young generation in under 1 millisecond for most web applications, making GC pauses nearly invisible to users.
Think about it: temporary variables, intermediate calculation results, short-lived callbacks. They're created, used briefly, and become garbage quickly. Only some objects (app state, cached data) live for a long time.
@@ -755,6 +759,32 @@ For most applications, `WeakMap` and `WeakSet` are better choices. They allow ob
---
+## Frequently Asked Questions
+
+
+
+ JavaScript uses the mark-and-sweep algorithm. The garbage collector starts from root references (global variables, the call stack, closures), marks all reachable objects as alive, then sweeps through memory and frees everything that wasn't marked. This process runs automatically — you cannot trigger it manually.
+
+
+
+ No. The ECMAScript specification provides no API for triggering garbage collection. The engine decides when to run GC based on memory pressure, idle time, and internal heuristics. Node.js exposes a `gc()` function with the `--expose-gc` flag for debugging, but this should never be used in production code.
+
+
+
+ No. The mark-and-sweep algorithm handles circular references correctly because it determines reachability from roots, not reference counts. Two objects that reference each other but are unreachable from any root will both be collected. Circular reference leaks only affected old browsers like IE6/7 that used reference counting.
+
+
+
+ Minor GC (the Scavenger in V8) runs frequently on the young generation where most short-lived objects reside — it typically completes in under 1 millisecond. Major GC (Mark-Compact) runs less often on the entire heap and is more thorough but slower. According to the V8 blog, this generational approach minimizes pause times significantly.
+
+
+
+ WeakMap and WeakSet hold "weak" references to their keys, meaning those keys can still be garbage collected when no other references exist. This makes them ideal for caches and metadata storage where you don't want your data structure to prevent cleanup of objects owned by other code.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/getters-setters.mdx b/docs/beyond/concepts/getters-setters.mdx
index 0123879d..eed81ac3 100644
--- a/docs/beyond/concepts/getters-setters.mdx
+++ b/docs/beyond/concepts/getters-setters.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Objects & Properties"
+"article:tag": "javascript getters setters, computed properties, property accessors, data validation, encapsulation"
---
How do you create a property that calculates its value on the fly? What if you want to validate data every time someone assigns a value? And how do you make a property that looks normal but does something behind the scenes?
@@ -47,7 +51,7 @@ console.log(user.fullName) // "Bob Smith"
## What Are Getters and Setters?
-**Getters** and **setters** are functions disguised as properties. When you access a getter, JavaScript calls the function and returns its result. When you assign to a setter, JavaScript calls the function with the assigned value. The key difference from regular methods is the syntax: no parentheses.
+**Getters** and **setters** are functions disguised as properties. When you access a getter, JavaScript calls the function and returns its result. When you assign to a setter, JavaScript calls the function with the assigned value. The key difference from regular methods is the syntax: no parentheses. According to the [ECMAScript specification](https://tc39.es/ecma262/#sec-method-definitions), getters and setters are defined as special method types within object literals and class bodies, creating accessor property descriptors rather than data descriptors.
```javascript
const circle = {
@@ -862,7 +866,7 @@ console.log(child.value) // "parent" — inherited getter now visible
### Getters Are Called Every Time
-Unlike regular properties, getters execute their function on every access:
+Unlike regular properties, getters execute their function on every access. MDN documents that getter functions are called each time the property is accessed, which means expensive computations inside getters can become a performance bottleneck if not cached:
```javascript
let callCount = 0
@@ -969,7 +973,7 @@ const point = {
## JSON.stringify() and Getters
-When you call [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) on an object, getter values are included in the output (because the getter is called), but setter-only properties result in nothing being included:
+When you call [`JSON.stringify()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) on an object, getter values are included in the output (because the getter is called), but setter-only properties result in nothing being included. As the ECMAScript specification defines, `JSON.stringify()` reads enumerable own properties, which triggers getter functions during serialization:
```javascript
const user = {
@@ -1142,6 +1146,32 @@ console.log(JSON.stringify(user))
---
+## Frequently Asked Questions
+
+
+
+ Getters are accessed without parentheses (`obj.area`) while methods require them (`obj.calculateArea()`). Semantically, use getters for values that feel like properties (area, fullName, isValid) and methods for actions (calculate, fetch, process). According to MDN, getters define an accessor property, not a data property.
+
+
+
+ Use a backing property with a different name (conventionally prefixed with `_`). For example, a `name` getter should read from `this._name`, not `this.name`. In modern classes, you can use private fields (`#name`) instead. Writing `this.name = value` inside a `name` setter calls the setter recursively, causing a stack overflow.
+
+
+
+ Yes. Unlike data properties, getters execute their function on every access. For expensive computations, this can become a bottleneck. MDN recommends using memoization or the self-replacing getter pattern to cache results. For values accessed in tight loops, consider using a regular data property instead.
+
+
+
+ Yes. `JSON.stringify()` triggers getter functions and includes their return values in the output. Setter-only properties produce no output since there is no value to serialize. This behavior is defined by the ECMAScript specification's property enumeration algorithm.
+
+
+
+ Yes. A getter-only property is effectively read-only. In strict mode, attempting to assign to it throws a `TypeError`. In non-strict mode, the assignment silently fails. This pattern is common for computed values like `area` on a shape object that should be derived, not directly set.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/hoisting.mdx b/docs/beyond/concepts/hoisting.mdx
index 5798a96d..b2958f1f 100644
--- a/docs/beyond/concepts/hoisting.mdx
+++ b/docs/beyond/concepts/hoisting.mdx
@@ -2,6 +2,10 @@
title: "Hoisting in JavaScript"
sidebarTitle: "Hoisting: How Declarations Move to the Top"
description: "Learn JavaScript hoisting: how var, let, const, and function declarations are moved to the top of their scope. Understand the Temporal Dead Zone."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Language Mechanics"
+"article:tag": "javascript hoisting, var hoisting, function hoisting, temporal dead zone, declaration vs initialization, scope hoisting"
---
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?
@@ -44,7 +48,7 @@ The answer is **hoisting**. It's one of JavaScript's most misunderstood behavior
## What is Hoisting in JavaScript?
-**[Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)** is JavaScript's behavior of moving declarations to the top of their scope during the compilation phase, before any code is executed. When JavaScript prepares to run your code, it first scans for all variable and function declarations and "hoists" them to the top of their containing scope. Only the declarations are hoisted, not the initializations.
+**[Hoisting](https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)** is JavaScript's behavior of moving declarations to the top of their scope during the compilation phase, before any code is executed. When JavaScript prepares to run your code, it first scans for all variable and function declarations and "hoists" them to the top of their containing scope. Only the declarations are hoisted, not the initializations. According to the [ECMAScript specification](https://tc39.es/ecma262/#sec-variable-statement), variable declarations are instantiated when their containing environment record is created, which is why they appear to "move" to the top.
Here's the key insight: hoisting isn't actually moving your code around. It's about when JavaScript becomes *aware* of your variables and functions during its two-phase execution process.
@@ -121,7 +125,7 @@ Let's explore each one in detail.
## Variable Hoisting with var
-Variables declared with [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) are hoisted to the top of their function (or global scope) and automatically initialized to `undefined`.
+Variables declared with [`var`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var) are hoisted to the top of their function (or global scope) and automatically initialized to `undefined`. As MDN documents, `var` declarations are processed before any code is executed, which is why accessing a `var` variable before its declaration returns `undefined` rather than throwing an error.
```javascript
console.log(greeting) // undefined (not an error!)
@@ -567,7 +571,7 @@ This two-phase approach is why hoisting exists. It's a natural consequence of ho
var counter = 0
```
- `const` and `let` have more predictable scoping and the TDZ catches bugs early.
+ `const` and `let` have more predictable scoping and the TDZ catches bugs early. The State of JS 2023 survey shows that over 93% of developers now regularly use `const` and `let`, reflecting a strong industry shift away from `var`.
@@ -758,6 +762,32 @@ This two-phase approach is why hoisting exists. It's a natural consequence of ho
---
+## Frequently Asked Questions
+
+
+
+ Hoisting is JavaScript's default behavior of moving variable and function declarations to the top of their scope during the compilation phase. Only the declarations are hoisted, not the initializations. According to MDN, this means variables can appear to be used before they are declared.
+
+
+
+ Yes, `let` and `const` are hoisted, but they are not initialized. They enter the Temporal Dead Zone (TDZ) from the start of their block until the declaration is reached. Accessing them before initialization throws a `ReferenceError`, unlike `var` which returns `undefined`.
+
+
+
+ Function declarations are fully hoisted — both the name and the body are available before the declaration appears in code. Function expressions follow variable hoisting rules: a `var` function expression is hoisted as `undefined`, while a `let`/`const` expression enters the TDZ. The ECMAScript specification treats function declarations differently because they are instantiated during environment setup.
+
+
+
+ No. Hoisting is a conceptual model describing observable behavior. The ECMAScript specification does not use the term "hoisting." Instead, JavaScript engines process declarations during a compilation phase before executing code, creating the effect of declarations being "moved" to the top.
+
+
+
+ When a `var` variable is hoisted, it is immediately initialized to `undefined`. This was a design choice in early JavaScript (1995) to be forgiving to developers. Modern `let` and `const` fixed this by introducing the TDZ, which catches accidental use of uninitialized variables with a `ReferenceError`.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/indexeddb.mdx b/docs/beyond/concepts/indexeddb.mdx
index 5bedc9b4..3a043798 100644
--- a/docs/beyond/concepts/indexeddb.mdx
+++ b/docs/beyond/concepts/indexeddb.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Browser Storage"
+"article:tag": "indexeddb, client-side database, structured data, transactions, offline storage"
---
What happens when localStorage's 5MB limit isn't enough? How do you store thousands of records, search them efficiently, or keep an app working offline with real data?
@@ -25,7 +29,7 @@ request.onsuccess = (event) => {
}
```
-IndexedDB is the backbone of offline-first applications, Progressive Web Apps (PWAs), and any app that needs to work without a network connection. It's more complex than localStorage, but far more powerful.
+IndexedDB is the backbone of offline-first applications, Progressive Web Apps (PWAs), and any app that needs to work without a network connection. According to Can I Use, IndexedDB has over 96% global browser support. It's more complex than localStorage, but far more powerful.
**What you'll learn in this guide:**
@@ -46,7 +50,7 @@ IndexedDB is the backbone of offline-first applications, Progressive Web Apps (P
## What is IndexedDB?
-**IndexedDB** is a low-level browser API for storing large amounts of structured data on the client side. It's a transactional, NoSQL database that uses object stores (similar to tables) to organize data, supports indexes for efficient queries, and can store almost any JavaScript value including objects, arrays, files, and blobs.
+**IndexedDB** is a low-level browser API for storing large amounts of structured data on the client side. As MDN documents, it's a transactional, NoSQL database that uses object stores (similar to tables) to organize data, supports indexes for efficient queries, and can store almost any JavaScript value including objects, arrays, files, and blobs.
Think of IndexedDB as a real database that lives in the browser. While [localStorage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) gives you a simple string-only key-value store with ~5MB limit, IndexedDB can store gigabytes of structured data with proper querying capabilities.
@@ -514,7 +518,7 @@ IDBKeyRange.bound(5, 10, true, false) // 5 < key <= 10
## Using Promise Wrappers
-The callback-based API can get messy. Most developers use a Promise wrapper library. The most popular is **idb** by Jake Archibald:
+The callback-based API can get messy. Most developers use a Promise wrapper library. The most popular is **idb** by Jake Archibald, a Chrome engineer whose library weighs only ~1.2kB and has been recommended by Google's web.dev team:
```javascript
// Using the idb library (https://github.com/jakearchibald/idb)
@@ -956,6 +960,32 @@ request.onupgradeneeded = (event) => {
---
+## Frequently Asked Questions
+
+
+
+ IndexedDB is used for storing large amounts of structured data in the browser — offline-first applications, caching API responses, storing files and blobs, and any scenario where localStorage's 5MB string-only limit is insufficient. It's the primary storage API for Progressive Web Apps (PWAs) that need to work without a network connection.
+
+
+
+ IndexedDB can store gigabytes of data, far exceeding localStorage's ~5MB limit. According to MDN's storage quotas documentation, browsers typically allow up to 50% of available disk space per origin. Chrome allocates up to 80% of total disk space across all origins, with individual origins limited to 60% of that.
+
+
+
+ IndexedDB is fully asynchronous and never blocks the main thread. It uses an event-based API with callbacks (`onsuccess`, `onerror`), though most developers use Promise wrappers like the `idb` library for cleaner async/await code. This asynchronous design is a key advantage over localStorage, which is synchronous.
+
+
+
+ Transactions auto-commit when there are no pending requests and JavaScript returns to the event loop. A `fetch()` call yields to the event loop, causing the transaction to close before the network response arrives. Always fetch data first, then open a transaction and write to IndexedDB.
+
+
+
+ `add()` inserts a new record and fails with an error if a record with the same key already exists. `put()` inserts or updates — it overwrites existing records silently. Use `add()` when you expect unique records and want errors on duplicates; use `put()` for upsert behavior.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/intersection-observer.mdx b/docs/beyond/concepts/intersection-observer.mdx
index f66ffb52..fefe518a 100644
--- a/docs/beyond/concepts/intersection-observer.mdx
+++ b/docs/beyond/concepts/intersection-observer.mdx
@@ -2,6 +2,10 @@
title: "Intersection Observer in JavaScript"
sidebarTitle: "Intersection Observer"
description: "Learn the Intersection Observer API in JavaScript. Implement lazy loading, infinite scroll, and scroll animations without scroll events."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Observer APIs"
+"article:tag": "intersection observer api, lazy loading images, infinite scroll, scroll detection, viewport visibility"
---
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?
@@ -38,7 +42,7 @@ The **[Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/A
## What is Intersection Observer in JavaScript?
-The **[Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)** is a browser API that lets you detect when an element enters, exits, or crosses a certain visibility threshold within a viewport or container element. Instead of constantly checking element positions during scroll events, the browser efficiently notifies your code only when visibility actually changes. **In short: Intersection Observer tells you when elements become visible or hidden, without the performance cost of scroll listeners.**
+The **[Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)** is a browser API that lets you detect when an element enters, exits, or crosses a certain visibility threshold within a viewport or container element. Instead of constantly checking element positions during scroll events, the browser efficiently notifies your code only when visibility actually changes. [Can I Use data](https://caniuse.com/intersectionobserver) shows the API is supported in over 97% of browsers globally. **In short: Intersection Observer tells you when elements become visible or hidden, without the performance cost of scroll listeners.**
---
@@ -98,7 +102,7 @@ window.addEventListener('scroll', () => {
└─────────────────────────────────────────────────────────────────────────────┘
```
-**Intersection Observer runs off the main thread** and is optimized by the browser, making it dramatically more efficient.
+**Intersection Observer runs off the main thread** and is optimized by the browser, making it dramatically more efficient. According to [web.dev](https://web.dev/articles/intersectionobserver-v2), Google introduced the API specifically to address the performance problems of scroll-based visibility detection, which was a leading cause of jank on content-heavy pages.
---
@@ -974,6 +978,32 @@ For legacy browser support, use the [official polyfill](https://github.com/w3c/I
---
+## Frequently Asked Questions
+
+
+
+ Intersection Observer detects when elements enter or leave the viewport (or a container element). Common use cases include lazy loading images, infinite scroll, scroll-triggered animations, and ad viewability tracking. According to web.dev, it replaces expensive scroll event listeners with browser-optimized callbacks.
+
+
+
+ Yes. Scroll events fire 60+ times per second and force layout recalculations via `getBoundingClientRect()`, causing jank and battery drain. Intersection Observer runs off the main thread, only fires when visibility actually changes, and is optimized by the browser. MDN recommends it as the modern replacement for scroll-based visibility detection.
+
+
+
+ `rootMargin` grows or shrinks the detection area around the root element, using CSS margin syntax. Positive values (e.g., `'100px'`) trigger callbacks before elements reach the viewport — ideal for preloading images. Negative values delay detection until elements are fully inside the viewport.
+
+
+
+ The callback fires once when you call `observe()` to report the element's current intersection state. This is intentional — as MDN documents, it lets you know the initial visibility without waiting for a scroll event. Always check `entry.isIntersecting` before acting.
+
+
+
+ Call `observer.unobserve(element)` to stop watching a specific element (ideal after lazy loading), or `observer.disconnect()` to stop all observation. In React, return a cleanup function from `useEffect` that calls `disconnect()`. Failing to clean up causes memory leaks.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/javascript-type-nuances.mdx b/docs/beyond/concepts/javascript-type-nuances.mdx
index 16e8f440..9a4f2074 100644
--- a/docs/beyond/concepts/javascript-type-nuances.mdx
+++ b/docs/beyond/concepts/javascript-type-nuances.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Type System"
+"article:tag": "javascript types, typeof operator, null undefined, nullish coalescing, optional chaining, bigint symbols"
---
Why does `typeof null` return `'object'`? Why does `0 || 'default'` give you `'default'` when `0` is a perfectly valid value? And why do Symbols exist when we already have strings for object keys?
@@ -305,7 +309,7 @@ isAdmin && deleteButton.show() // Only call if isAdmin is truthy
### Nullish Coalescing (??) — Only null/undefined
-The [`??`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) operator is the modern solution. It only falls back when the left side is `null` or `undefined`:
+The [`??`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing) operator is the modern solution, introduced in ES2020. According to the [V8 blog](https://v8.dev/features/nullish-coalescing), the nullish coalescing operator was one of the most requested features by the JavaScript community. It only falls back when the left side is `null` or `undefined`:
```javascript
// Only null and undefined trigger the fallback
@@ -450,7 +454,7 @@ This is JavaScript's most famous quirk:
typeof null // 'object' — NOT 'null'!
```
-This is a bug from the first version of JavaScript in 1995. In the original implementation, values were stored with a type tag. Objects had a type tag of `0`. `null` was represented as the NULL pointer (`0x00`), which also had a type tag of `0`. So `typeof null` returned `'object'`.
+This is a bug from the first version of JavaScript in 1995. In the original implementation, values were stored with a type tag. Objects had a type tag of `0`. `null` was represented as the NULL pointer (`0x00`), which also had a type tag of `0`. So `typeof null` returned `'object'`. As Dr. Axel Rauschmayer documented in his analysis of the [original JavaScript source code](https://2ality.com/2013/10/typeof-null.html), a proposal to fix this (typeof null === 'null') was rejected by TC39 because it would break an estimated 10% of existing websites.
Fixing this bug would break too much existing code, so it remains. To properly check for `null`:
@@ -647,7 +651,7 @@ invalid instanceof ValidUser // false
## Symbols: Unique Identifiers
-[`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) is a primitive type that creates guaranteed unique identifiers. Every `Symbol()` call creates a new, unique value.
+[`Symbol`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) is a primitive type introduced in ES2015 that creates guaranteed unique identifiers. Every `Symbol()` call creates a new, unique value. According to MDN, Symbols are the only primitive type that serves as a non-string property key, making them essential for metaprogramming and avoiding property name collisions in shared codebases.
### Creating Symbols
@@ -1137,6 +1141,36 @@ factorial(100n) // Huge number, no precision loss!
---
+## Frequently Asked Questions
+
+
+
+ This is a well-known bug dating back to the original JavaScript implementation in 1995. Values were stored with type tags, and `null` used the same tag (`0`) as objects. A TC39 proposal to fix this was rejected because it would have broken too many existing websites. Use `value === null` to check for null instead of `typeof`.
+
+
+
+ Using `== null` (loose equality) checks for both `null` and `undefined` in one condition — this is because the ECMAScript specification defines `null == undefined` as `true`. Using `=== null` (strict equality) only matches `null`. Most style guides recommend `== null` as the one acceptable use of loose equality.
+
+
+
+ Use `??` (nullish coalescing) when `0`, `""`, or `false` are valid values you want to preserve. The `||` operator replaces any falsy value, while `??` only replaces `null` and `undefined`. For example, `userCount ?? 10` keeps `0` as a valid count, whereas `userCount || 10` would replace it with `10`.
+
+
+
+ Symbols create guaranteed unique property keys that prevent name collisions between different parts of a codebase. They are also used as "well-known symbols" (like `Symbol.iterator` and `Symbol.hasInstance`) to customize built-in JavaScript behavior. MDN documents 13 well-known symbols in the current specification.
+
+
+
+ No. JavaScript throws a `TypeError` if you try to combine BigInt and Number in arithmetic operations like `10n + 5`. This is a deliberate design choice to prevent accidental precision loss. You must explicitly convert using `BigInt(5)` or `Number(10n)` before combining them.
+
+
+
+ The recommended approach is to use `value == null`, which catches both `null` and `undefined` thanks to JavaScript's loose equality rules. Alternatively, use `value ?? 'default'` with nullish coalescing to provide a fallback value. For property access, use optional chaining (`obj?.prop`) to avoid `TypeError` on null or undefined objects.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/json-deep-dive.mdx b/docs/beyond/concepts/json-deep-dive.mdx
index a0b2ed9b..08f51313 100644
--- a/docs/beyond/concepts/json-deep-dive.mdx
+++ b/docs/beyond/concepts/json-deep-dive.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Data Handling"
+"article:tag": "json stringify parse, json replacer reviver, circular references, tojson method, serialization"
---
How do you filter sensitive data when sending objects to an API? How do you revive Date objects from a JSON string? What happens when you try to stringify an object with circular references?
@@ -39,7 +43,7 @@ These are everyday challenges when working with **[JSON](https://developer.mozil
## What is JSON?
-**JSON** (JavaScript Object Notation) is a lightweight text format for storing and exchanging data. It's language-independent but derived from JavaScript syntax. JSON has become the standard format for APIs, configuration files, and data storage across the web.
+**JSON** (JavaScript Object Notation) is a lightweight text format for storing and exchanging data. Originally specified by Douglas Crockford and formalized in [ECMA-404](https://ecma-international.org/publications-and-standards/standards/ecma-404/) and [RFC 8259](https://datatracker.ietf.org/doc/html/rfc8259), JSON is language-independent but derived from JavaScript syntax. JSON has become the standard format for APIs, configuration files, and data storage across the web.
```javascript
// JSON is just text that represents data
@@ -55,7 +59,7 @@ console.log(backToJSON) // '{"name":"Alice","age":30,"isAdmin":true}'
```
-**JSON vs JavaScript Objects:** JSON syntax is a subset of JavaScript. All JSON is valid JavaScript, but not all JavaScript objects can be represented as JSON. Functions, `undefined`, Symbols, and circular references don't have JSON equivalents.
+**JSON vs JavaScript Objects:** JSON syntax is a strict subset of JavaScript. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON), all JSON is valid JavaScript, but not all JavaScript objects can be represented as JSON. Functions, `undefined`, Symbols, and circular references don't have JSON equivalents.
---
@@ -965,6 +969,32 @@ safeLog({
---
+## Frequently Asked Questions
+
+
+
+ `JSON.stringify()` silently omits properties whose values are `undefined`, functions, or Symbols. In arrays, these values are replaced with `null`. MDN documents this behavior as part of the serialization algorithm defined in the ECMA-262 specification.
+
+
+
+ A replacer is the optional second argument to `JSON.stringify()` — either a function or an array. A function receives each key-value pair and can transform or exclude values by returning `undefined`. An array acts as a whitelist, including only the listed property names in the output.
+
+
+
+ `JSON.stringify()` throws a `TypeError` when it encounters circular references. Solutions include using a replacer function that tracks seen objects, libraries like `flatted` or `circular-json`, or restructuring your data to eliminate cycles before serialization.
+
+
+
+ The reviver is an optional second argument to `JSON.parse()` that transforms values during parsing. It's commonly used to convert ISO date strings back into `Date` objects. The reviver function receives each key-value pair and returns the transformed value.
+
+
+
+ Pass a third argument to `JSON.stringify()` for indentation: `JSON.stringify(data, null, 2)` adds 2-space indentation. You can use a number (1-10) for spaces or a string like `'\t'` for tabs. According to the ECMA-404 specification, whitespace in JSON is purely cosmetic.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/localstorage-sessionstorage.mdx b/docs/beyond/concepts/localstorage-sessionstorage.mdx
index 009dc6b3..eed2cec4 100644
--- a/docs/beyond/concepts/localstorage-sessionstorage.mdx
+++ b/docs/beyond/concepts/localstorage-sessionstorage.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Browser Storage"
+"article:tag": "localstorage sessionstorage, web storage api, persistent storage, json serialization, storage events"
---
How do you keep a user's dark mode preference when they return to your site? Why does your shopping cart persist across browser sessions, but form data vanishes when you close a tab? How do modern web apps remember state without constantly calling the server?
@@ -21,7 +25,7 @@ console.log(localStorage.length) // 1
console.log(sessionStorage.length) // 1
```
-The answer is the **[Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)**. It's one of the most practical browser APIs you'll use daily, and understanding when to use `localStorage` vs `sessionStorage` will make your applications more user-friendly and performant.
+The answer is the **[Web Storage API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)**. Supported by over 97% of browsers worldwide according to Can I Use, it's one of the most practical browser APIs you'll use daily, and understanding when to use `localStorage` vs `sessionStorage` will make your applications more user-friendly and performant.
**What you'll learn in this guide:**
@@ -44,7 +48,7 @@ The answer is the **[Web Storage API](https://developer.mozilla.org/en-US/docs/W
**[Web Storage](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API)** is a browser API that allows JavaScript to store key-value pairs locally in the user's browser. Unlike cookies, stored data is never sent to the server with HTTP requests. Web Storage provides two mechanisms: `localStorage` for persistent storage that survives browser restarts, and `sessionStorage` for temporary storage that is cleared when the browser tab closes.
-Here's the key insight: Web Storage is synchronous, string-only, and scoped to the origin (protocol + domain + port). These constraints make it simple to use but require understanding for effective implementation.
+Here's the key insight: Web Storage is synchronous, string-only, and scoped to the origin (protocol + domain + port). As MDN documents, these constraints make it simple to use but require understanding for effective implementation — particularly the synchronous nature, which can block the main thread with large data operations.
Web Storage has been available in all major browsers since July 2015. It's part of the HTML5 specification and is considered a "Baseline" feature—meaning you can rely on it working everywhere.
@@ -596,7 +600,7 @@ for (let i = 0; i < localStorage.length; i++) {
4. **Sanitize all user input**: Never trust data from users
5. **Consider encryption for semi-sensitive data**: Though this adds complexity
-For comprehensive security guidance, see the [OWASP HTML5 Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage).
+The OWASP Foundation explicitly recommends against storing sensitive data in Web Storage. For comprehensive security guidance, see the [OWASP HTML5 Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTML5_Security_Cheat_Sheet.html#local-storage).
---
@@ -908,6 +912,32 @@ function getRecentlyViewed() {
---
+## Frequently Asked Questions
+
+
+
+ `localStorage` persists data until explicitly cleared — it survives browser restarts and remains across all tabs from the same origin. `sessionStorage` is isolated to a single tab and cleared when that tab closes. Both share the same API and a ~5MB storage limit per origin.
+
+
+
+ Most browsers provide approximately 5–10 MB per origin (protocol + domain + port). According to MDN, the exact limit varies by browser but is typically 5 MB. When you exceed this limit, `setItem()` throws a `QuotaExceededError` that you should handle with try-catch.
+
+
+
+ No. The OWASP Foundation explicitly warns against storing sensitive data in Web Storage. Any JavaScript running on the page — including malicious scripts injected through XSS attacks — can read localStorage. Authentication tokens should be stored in HTTP-only cookies, which are inaccessible to JavaScript.
+
+
+
+ Behavior varies by browser. Safari may throw a `QuotaExceededError` on any write attempt in private mode. Chrome and Firefox allow localStorage but clear all data when the private window closes. Always use feature detection with try-catch before relying on localStorage.
+
+
+
+ Use `JSON.stringify()` when saving and `JSON.parse()` when retrieving. localStorage can only store strings — storing an object directly converts it to the useless string `"[object Object]"`. Be aware that `Date` objects, `undefined` values, and functions are not preserved through JSON serialization.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/memoization.mdx b/docs/beyond/concepts/memoization.mdx
index e359a754..b9a8893e 100644
--- a/docs/beyond/concepts/memoization.mdx
+++ b/docs/beyond/concepts/memoization.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Memory & Performance"
+"article:tag": "memoization, function caching, performance optimization, usememo, expensive computations"
---
Why does a naive Fibonacci function take forever for large numbers while a memoized version finishes instantly? Why do some React components re-render unnecessarily while others stay perfectly optimized?
@@ -48,7 +52,7 @@ Memoization is built on [closures](/concepts/scope-and-closures), uses data stru
## What is Memoization?
-**Memoization** is an optimization technique that speeds up programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again. The term comes from the Latin word "memorandum" (to be remembered), which is also the root of "memo."
+**Memoization** is an optimization technique that speeds up programs by storing the results of expensive function calls and returning the cached result when the same inputs occur again. The term was coined by Donald Michie in 1968, derived from the Latin word "memorandum" (to be remembered), which is also the root of "memo."
Think of memoization as giving your function a notepad. Before doing any calculation, the function checks its notes: "Have I solved this exact problem before?" If yes, it reads the answer from the notepad. If no, it calculates the result, writes it down, and then returns it.
@@ -258,7 +262,7 @@ function fibonacci(n) {
// fib(2) is calculated THREE times
```
-For `fibonacci(40)`, the naive version makes over 300 million function calls because it recalculates the same values repeatedly.
+For `fibonacci(40)`, the naive version makes over 330 million function calls because it recalculates the same values repeatedly. According to computer science research, this transforms O(2^n) exponential time complexity into O(n) linear time — a reduction of over 99.99% in function calls.
### The Solution: Memoized Fibonacci
@@ -626,7 +630,7 @@ const factorial = memoize(function(n) {
## Advanced: LRU Cache for Bounded Memory
-Standard memoization caches grow unbounded. For production use, consider a Least Recently Used (LRU) cache that evicts old entries:
+Standard memoization caches grow unbounded. As MDN's documentation on Map notes, Map maintains insertion order, which makes it an ideal foundation for building LRU (Least Recently Used) caches that evict old entries:
```javascript
function memoizeLRU(fn, maxSize = 100) {
@@ -799,6 +803,32 @@ This implementation leverages the fact that [`Map`](https://developer.mozilla.or
---
+## Frequently Asked Questions
+
+
+
+ Memoization is an optimization technique that caches the results of function calls and returns the cached result when the same inputs occur again. It trades memory for speed by storing previous computations. The technique was formalized by Donald Michie in 1968 and is widely used in dynamic programming and UI frameworks like React.
+
+
+
+ Memoization is a specific form of caching that stores function return values based on their input arguments. General caching can apply to any data (API responses, database queries, files). Memoization is tied to function purity — it only works correctly when the same inputs always produce the same output with no side effects.
+
+
+
+ Pure functions always return the same output for the same input and have no side effects. If you memoize an impure function that depends on external state, the cached result becomes stale when that state changes. Side effects (like logging or API calls) are also skipped on cache hits, which can break expected behavior.
+
+
+
+ Yes, but use `WeakMap` instead of `Map` for the cache. `JSON.stringify` loses object identity and prevents garbage collection. MDN documents that WeakMap keys are held weakly, meaning objects can be garbage collected when no other references exist, preventing memory leaks in long-running applications.
+
+
+
+ Avoid memoizing fast functions where cache lookup overhead exceeds computation time, functions with always-unique inputs that fill the cache without providing hits, functions with side effects, and impure functions that depend on external state. Measure before and after to confirm memoization actually helps.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/memory-management.mdx b/docs/beyond/concepts/memory-management.mdx
index 44600e5d..a7ccec21 100644
--- a/docs/beyond/concepts/memory-management.mdx
+++ b/docs/beyond/concepts/memory-management.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Memory & Performance"
+"article:tag": "memory management, javascript memory, stack heap, memory leaks, devtools profiling"
---
Why does your web app slow down over time? Why does that single-page application become sluggish after hours of use? The answer often lies in **memory management**, the invisible system that allocates and frees memory as your code runs.
@@ -16,7 +20,7 @@ let count = 42; // Primitive stored in stack
// JavaScript handles cleanup automatically... most of the time
```
-Unlike languages like C where you manually allocate and free memory, JavaScript handles this automatically. But "automatic" doesn't mean "worry-free." Understanding how memory management works helps you write faster, more efficient code and avoid the dreaded memory leaks that crash applications.
+Unlike languages like C where you manually allocate and free memory, JavaScript handles this automatically. But "automatic" doesn't mean "worry-free." According to the State of JS 2023 survey, memory management and performance optimization remain among the top pain points reported by JavaScript developers. Understanding how memory management works helps you write faster, more efficient code and avoid the dreaded memory leaks that crash applications.
**What you'll learn in this guide:**
@@ -288,7 +292,7 @@ function example() {
### The Mark-and-Sweep Algorithm
-Modern JavaScript engines use the **mark-and-sweep** algorithm:
+Modern JavaScript engines use the **mark-and-sweep** algorithm. As MDN documents, this approach replaced the older reference-counting strategy because it correctly handles circular references — a limitation that caused notorious memory leaks in early Internet Explorer versions:
```
┌─────────────────────────────────────────────────────────────────────────┐
@@ -574,7 +578,7 @@ JavaScript provides special data structures designed for memory efficiency:
### WeakMap and WeakSet
-[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) and [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) hold "weak" references that don't prevent garbage collection:
+[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) and [`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet), introduced in the ECMAScript 2015 specification, hold "weak" references that don't prevent garbage collection:
```javascript
// WeakMap: Associate data with objects without preventing GC
@@ -950,6 +954,32 @@ To find memory leaks:
---
+## Frequently Asked Questions
+
+
+
+ The most common causes are forgotten event listeners, uncleared timers and intervals, detached DOM elements still referenced in JavaScript, closures that capture large objects, and unbounded caches. According to Chrome DevTools documentation, detached DOM nodes are one of the most frequently identified leak sources in heap snapshot analysis.
+
+
+
+ Use the Chrome DevTools Memory panel to take heap snapshots and compare them over time. Look for objects with unexpectedly high retained size, detached DOM nodes, and growing object counts between snapshots. The Allocation Timeline tool helps identify where allocations originate in your code.
+
+
+
+ The stack stores primitive values and function call frames with fast, ordered LIFO access. The heap stores objects, arrays, and functions with dynamic sizing managed by the garbage collector. Variables on the stack hold references (pointers) to objects in the heap, which is why reassigning an object variable doesn't copy the object.
+
+
+
+ No. JavaScript uses automatic memory management through garbage collection. The ECMAScript specification does not expose any API for manual allocation or deallocation. However, you can help the garbage collector by nullifying references to large objects when done and cleaning up event listeners and timers.
+
+
+
+ There is no fixed limit defined by the language. Browser tabs typically have access to 1–4 GB of heap memory depending on the device and browser. Node.js defaults to approximately 1.5 GB on 64-bit systems but can be increased with the `--max-old-space-size` flag. MDN recommends profiling regularly to avoid exceeding practical limits.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/mutation-observer.mdx b/docs/beyond/concepts/mutation-observer.mdx
index 8b86d43c..86274edf 100644
--- a/docs/beyond/concepts/mutation-observer.mdx
+++ b/docs/beyond/concepts/mutation-observer.mdx
@@ -2,6 +2,10 @@
title: "MutationObserver in JavaScript"
sidebarTitle: "MutationObserver: Watching DOM Changes"
description: "Learn the MutationObserver API in JavaScript. Watch DOM changes, detect attribute modifications, and build reactive UIs."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Observer APIs"
+"article:tag": "mutationobserver, dom changes, attribute modifications, reactive ui, dom monitoring"
---
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?
@@ -68,7 +72,7 @@ Before MutationObserver, developers used **Mutation Events** (`DOMNodeInserted`,
| Performance killer | Made complex DOM updates painfully slow |
| Bubbled up the DOM | Caused cascade of unnecessary handlers |
-MutationObserver solves all of these by batching changes and delivering them asynchronously via microtasks.
+MutationObserver solves all of these by batching changes and delivering them asynchronously via microtasks. As the [original Mozilla Hacks blog post](https://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/) explains, this redesign was driven by real-world performance problems that Mutation Events caused in complex web applications.
---
@@ -437,7 +441,7 @@ class MyComponent {
## When Callbacks Run: Microtasks
-MutationObserver callbacks are scheduled as **microtasks**, meaning they run after the current script but before the browser renders. This is the same queue as Promise callbacks.
+MutationObserver callbacks are scheduled as **microtasks**, meaning they run after the current script but before the browser renders. According to the [WHATWG HTML specification](https://html.spec.whatwg.org/multipage/webappapis.html#mutation-observers), this batching behavior is intentional — it allows multiple DOM changes to be processed in a single callback invocation. This is the same queue as Promise callbacks.
```javascript
console.log('1. Script start')
@@ -852,6 +856,32 @@ observer.observe(specificContainer, {
---
+## Frequently Asked Questions
+
+
+
+ MutationObserver is a built-in API that watches a DOM element and fires a callback when specified changes occur — child nodes added or removed, attributes modified, or text content changed. It replaced the deprecated Mutation Events API, which was removed from the W3C specification due to severe performance problems.
+
+
+
+ Mutation Events (`DOMNodeInserted`, `DOMAttrModified`) fired synchronously on every single DOM change, blocking the main thread. MutationObserver batches changes and delivers them asynchronously as microtasks. MDN marks Mutation Events as deprecated and recommends MutationObserver as the only supported alternative.
+
+
+
+ Without `subtree: true`, MutationObserver only watches direct children of the target element. With `subtree: true`, it watches the entire descendant tree. Use subtree when changes can happen at any depth, but be specific about which element to observe to avoid performance overhead.
+
+
+
+ If your callback modifies the DOM in a way the observer is watching, it triggers another callback — creating a loop. Use `attributeFilter` to exclude attributes you modify, add a guard condition to skip processed elements, or temporarily disconnect before making changes and reconnect afterward.
+
+
+
+ Callbacks run as microtasks — after the current synchronous script finishes but before the browser paints. According to the WHATWG specification, multiple rapid DOM changes are batched into a single callback invocation, which is why MutationObserver is far more efficient than the synchronous Mutation Events it replaced.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/object-methods.mdx b/docs/beyond/concepts/object-methods.mdx
index 6e9a7f1f..e4c97220 100644
--- a/docs/beyond/concepts/object-methods.mdx
+++ b/docs/beyond/concepts/object-methods.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Objects & Properties"
+"article:tag": "object methods, object.keys, object.entries, object.assign, structuredclone, object manipulation"
---
How do you loop through an object's properties? How do you transform an object's keys? Or create a true copy of an object without unexpected side effects?
@@ -38,7 +42,7 @@ const upperKeys = Object.fromEntries(
## What are Object Methods?
-**Object methods** are static functions on JavaScript's built-in `Object` constructor that let you inspect, manipulate, and transform objects. Unlike instance methods you call on the object itself (like `toString()`), these are called on `Object` directly with the target object passed as an argument.
+**Object methods** are static functions on JavaScript's built-in `Object` constructor that let you inspect, manipulate, and transform objects. Unlike instance methods you call on the object itself (like `toString()`), these are called on `Object` directly with the target object passed as an argument. According to MDN, the `Object` constructor provides over 30 static methods, with new ones like `Object.groupBy()` added as recently as ES2024.
```javascript
const product = { name: 'Laptop', price: 999 }
@@ -258,7 +262,7 @@ console.log(original.address.city) // 'LA' — both changed!
### structuredClone() — Deep Copy
-[`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone) creates a true deep copy, including nested objects. It was added to browsers and Node.js in 2022.
+[`structuredClone()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/structuredClone) creates a true deep copy, including nested objects. It was added to browsers and Node.js in 2022. As the web.dev team documented, `structuredClone()` replaced the common `JSON.parse(JSON.stringify(obj))` workaround that failed with `Date`, `Map`, `Set`, `RegExp`, and circular references.
```javascript
const original = {
@@ -315,7 +319,7 @@ structuredClone(obj) // Throws: DataCloneError
## Object.hasOwn() — Safe Property Checking
-[`Object.hasOwn()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn) checks if an object has a property as its own (not inherited). It's the modern replacement for `hasOwnProperty()`.
+[`Object.hasOwn()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwn) checks if an object has a property as its own (not inherited). It's the modern replacement for `hasOwnProperty()`, introduced in ES2022. MDN recommends using `Object.hasOwn()` over `Object.prototype.hasOwnProperty()` in all new code because it works correctly with null-prototype objects and cannot be overridden.
```javascript
const user = { name: 'Alice', age: 30 }
@@ -713,6 +717,32 @@ function processData(data) {
---
+## Frequently Asked Questions
+
+
+
+ `Object.keys()` returns an array of property names (strings), while `Object.entries()` returns an array of `[key, value]` pairs. Use `Object.keys()` when you only need property names. Use `Object.entries()` when you need both keys and values, especially for transformations with `Object.fromEntries()`.
+
+
+
+ Use `structuredClone()`, which was added to all major browsers and Node.js in 2022. It creates a true deep copy that handles nested objects, circular references, `Date`, `Map`, and `Set` objects. The older `JSON.parse(JSON.stringify(obj))` workaround fails with these types and cannot handle functions.
+
+
+
+ `Object.groupBy()` groups array elements by a callback function's return value, creating an object where each key maps to an array of matching items. It was standardized in ES2024 (March 2024). According to MDN, check browser compatibility before using in production without a polyfill.
+
+
+
+ `Object.hasOwn()` is safer in two cases: it works on null-prototype objects (where `hasOwnProperty` does not exist), and it cannot be overridden by a property of the same name on the object. MDN recommends it as the standard replacement for `hasOwnProperty()` in all modern JavaScript code.
+
+
+
+ No. `Object.assign()` performs a shallow copy — only the top-level properties are copied. Nested objects are still shared by reference, meaning changes to nested properties in the copy affect the original. For independent nested copies, use `structuredClone()` instead.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/performance-observer.mdx b/docs/beyond/concepts/performance-observer.mdx
index da4592b1..fb548fde 100644
--- a/docs/beyond/concepts/performance-observer.mdx
+++ b/docs/beyond/concepts/performance-observer.mdx
@@ -2,6 +2,10 @@
title: "PerformanceObserver in JS"
sidebarTitle: "Performance Observer"
description: "Learn the Performance Observer API in JavaScript. Measure page performance, track Long Tasks, and collect Core Web Vitals metrics."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Observer APIs"
+"article:tag": "performanceobserver, core web vitals, long tasks, performance metrics, page speed"
---
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.
@@ -22,7 +26,7 @@ observer.observe({ type: 'resource', buffered: true })
// https://example.com/hero.webp: 412.80ms
```
-The **[Performance Observer API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver)** lets you monitor performance metrics as they happen in real-time. Instead of polling for data, you subscribe to specific performance events and get notified when they occur. This is the foundation of Real User Monitoring (RUM) and how tools like Google Analytics measure Core Web Vitals.
+The **[Performance Observer API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceObserver)** lets you monitor performance metrics as they happen in real-time. Instead of polling for data, you subscribe to specific performance events and get notified when they occur. According to [web.dev](https://web.dev/articles/custom-metrics), this is the foundation of Real User Monitoring (RUM) and how tools like Google Analytics measure Core Web Vitals.
**What you'll learn in this guide:**
@@ -216,7 +220,7 @@ paintObserver.observe({ type: 'paint', buffered: true })
## Measuring Core Web Vitals
-Core Web Vitals are Google's essential metrics for user experience. Performance Observer is how you measure them in the field.
+Core Web Vitals are Google's essential metrics for user experience. According to the [Chrome User Experience Report](https://developer.chrome.com/docs/crux/), sites meeting all three Core Web Vitals thresholds see 24% fewer page abandonment rates. Performance Observer is how you measure them in the field.
### Largest Contentful Paint (LCP)
@@ -960,6 +964,32 @@ if (shouldSample) {
---
+## Frequently Asked Questions
+
+
+
+ PerformanceObserver is a browser API that asynchronously observes performance measurement events — resource loading, paint timing, layout shifts, and more. It replaced the older polling-based `performance.getEntries()` approach with an event-driven callback model. MDN recommends it as the standard way to collect Real User Monitoring data.
+
+
+
+ Core Web Vitals are three metrics Google uses to evaluate user experience: LCP (Largest Contentful Paint, target under 2.5s), CLS (Cumulative Layout Shift, target under 0.1), and INP (Interaction to Next Paint, target under 200ms). All three can be measured using PerformanceObserver. For production use, Google recommends the `web-vitals` library.
+
+
+
+ The `buffered: true` option tells the browser to include performance entries recorded before you called `observe()`. Without it, you miss entries like FCP or LCP that occurred before your script loaded. Web.dev recommends always using `buffered: true` for metrics collection.
+
+
+
+ `navigator.sendBeacon()` is designed to reliably send data even when a page is unloading — unlike `fetch()`, which may be cancelled. MDN documents that `sendBeacon` uses a POST request that the browser guarantees to deliver, making it ideal for sending performance metrics on the `visibilitychange` event.
+
+
+
+ A Long Task is any JavaScript task that blocks the main thread for more than 50ms. During a Long Task, users cannot click, scroll, or type. According to web.dev, Long Tasks are the primary cause of poor INP scores. Monitor them with `observer.observe({ type: 'longtask' })` and break up heavy code into smaller chunks.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/property-descriptors.mdx b/docs/beyond/concepts/property-descriptors.mdx
index ba62aa05..feef678e 100644
--- a/docs/beyond/concepts/property-descriptors.mdx
+++ b/docs/beyond/concepts/property-descriptors.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Objects & Properties"
+"article:tag": "property descriptors, object.defineproperty, writable enumerable configurable, immutable properties, property flags"
---
Why can you delete most object properties but not `Math.PI`? Why do some properties show up in `for...in` loops while others don't? And how do you create a property that can never be changed?
@@ -49,7 +53,7 @@ console.log(descriptor)
## What are Property Descriptors?
-**Property descriptors** are metadata objects that describe the characteristics of an object property. Every property in JavaScript has a descriptor that controls whether the property can be changed, deleted, or enumerated. When you create a property the "normal" way (with assignment), JavaScript sets all flags to permissive defaults.
+**Property descriptors** are metadata objects that describe the characteristics of an object property. Every property in JavaScript has a descriptor that controls whether the property can be changed, deleted, or enumerated. When you create a property the "normal" way (with assignment), JavaScript sets all flags to permissive defaults. As defined in the [ECMAScript specification](https://tc39.es/ecma262/#sec-property-attributes), every property has internal attributes that determine its behavior — this mechanism is what powers built-in immutable properties like `Math.PI`.
```javascript
const user = { name: "Alice" }
@@ -344,7 +348,7 @@ console.log(Object.getOwnPropertyDescriptors(user))
### Cloning Objects with Descriptors
-The spread operator and `Object.assign()` don't preserve property descriptors. Use `Object.getOwnPropertyDescriptors()` for a true clone:
+The spread operator and `Object.assign()` don't preserve property descriptors. As documented by MDN, `Object.getOwnPropertyDescriptors()` was added in ES2017 specifically to enable proper cloning of objects including their accessor properties and flags:
```javascript
const original = {}
@@ -479,7 +483,7 @@ console.log(Object.isExtensible(user)) // false
### `Object.seal()`: No Add/Delete, Can Still Modify
-[`Object.seal()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) prevents adding or deleting properties by setting `configurable: false` on all existing properties:
+[`Object.seal()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) prevents adding or deleting properties by setting `configurable: false` on all existing properties. MDN notes that sealed objects are one of the most common patterns for creating configuration objects that should not have their structure modified at runtime:
```javascript
const config = { debug: true, version: 1 }
@@ -834,6 +838,32 @@ person.age = "old" // TypeError: Age must be a positive number
---
+## Frequently Asked Questions
+
+
+
+ Property descriptors are metadata objects that control how a property behaves — whether it can be modified (`writable`), shown in loops (`enumerable`), or reconfigured (`configurable`). The ECMAScript specification defines these as internal attributes that every object property has, which is how built-in properties like `Math.PI` remain immutable.
+
+
+
+ `Object.seal()` prevents adding or deleting properties but allows modifying existing values. `Object.freeze()` prevents all changes — no adding, deleting, or modifying. Both are shallow, meaning nested objects remain unaffected. According to MDN, `Object.freeze()` sets both `writable: false` and `configurable: false` on every property.
+
+
+
+ No. Setting `configurable: false` is permanent and irreversible. Once a property is non-configurable, you cannot delete it, change its enumerability, or switch it between data and accessor types. The only change still allowed is setting `writable` from `true` to `false` — never the reverse.
+
+
+
+ When using `Object.defineProperty()`, unspecified flags default to `false`, making properties restrictive by default. This is the opposite of normal assignment (where all flags default to `true`). MDN recommends always explicitly setting all flags you care about to avoid unexpected behavior from these defaults.
+
+
+
+ Yes. Non-enumerable properties are excluded from `JSON.stringify()` output, just as they are hidden from `Object.keys()` and `for...in` loops. However, `writable` and `configurable` flags have no effect on serialization. This is how JavaScript hides internal properties like `Array.prototype.length` from serialization.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/proxy-reflect.mdx b/docs/beyond/concepts/proxy-reflect.mdx
index c5f62ee4..324fe33a 100644
--- a/docs/beyond/concepts/proxy-reflect.mdx
+++ b/docs/beyond/concepts/proxy-reflect.mdx
@@ -2,6 +2,10 @@
title: "Proxy & Reflect in JavaScript"
sidebarTitle: "Proxy & Reflect: Intercepting Object Operations"
description: "Learn JavaScript Proxy and Reflect APIs. Intercept object operations, create reactive systems, and build powerful metaprogramming patterns."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Objects & Properties"
+"article:tag": "javascript proxy, reflect api, metaprogramming, handler traps, object interception, reactive systems"
---
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?
@@ -27,7 +31,7 @@ proxy.name // Logs: "Reading name", returns "Alice"
proxy.age = -5 // Error: Age cannot be negative
```
-This is the power of **[Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)** and **[Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)**. Proxies let you intercept and customize fundamental operations on objects, while Reflect provides the default behavior you can forward to. Together, they enable validation, logging, reactive data binding, and other metaprogramming patterns.
+This is the power of **[Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)** and **[Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)**. Proxies let you intercept and customize fundamental operations on objects, while Reflect provides the default behavior you can forward to. Together, they enable validation, logging, reactive data binding, and other metaprogramming patterns. According to the ECMAScript specification, Proxy traps map directly to [internal methods](https://tc39.es/ecma262/#sec-proxy-object-internal-methods-and-internal-slots) that define how all JavaScript objects behave at the engine level.
**What you'll learn in this guide:**
@@ -347,7 +351,7 @@ console.log(Object.keys(safeUser)) // ["name", "age"] - _password hidden
## Why Reflect Exists
-**[Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)** is a built-in object with methods that mirror every Proxy trap. It provides the default behavior you'd otherwise have to implement manually.
+**[Reflect](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect)** is a built-in object with methods that mirror every Proxy trap. It provides the default behavior you'd otherwise have to implement manually. MDN documents that Reflect was introduced alongside Proxy in ES2015 specifically to provide a clean, function-based API for object operations that previously required operators or `Object.*` methods.
| Operation | Without Reflect | With Reflect |
|-----------|-----------------|--------------|
@@ -404,7 +408,7 @@ const proxy = new Proxy(user, {
### Observable Objects (Reactive Data)
-Create objects that notify you when they change. This is how frameworks like Vue.js implement reactivity:
+Create objects that notify you when they change. This is how frameworks like Vue.js implement reactivity. According to the Vue.js documentation, Vue 3 replaced `Object.defineProperty()` (used in Vue 2) with `Proxy` for its reactivity system, enabling detection of property additions and deletions that were previously impossible:
```javascript
function observable(target, onChange) {
@@ -714,6 +718,32 @@ console.log(set.has(proxy)) // false - they're different objects
---
+## Frequently Asked Questions
+
+
+
+ A Proxy is a wrapper around an object (the "target") that intercepts fundamental operations like property access, assignment, and deletion. You define custom behavior through "trap" methods in a handler object. According to the ECMAScript specification, Proxy traps correspond to 13 internal object methods, covering every way JavaScript interacts with objects.
+
+
+
+ `Reflect` methods properly forward the `receiver` parameter, which is essential when the target has getters that use `this`. Using `target[prop]` directly can cause `this` to reference the wrong object in inheritance chains. MDN recommends always using `Reflect.get()` and `Reflect.set()` inside Proxy traps for correct behavior.
+
+
+
+ Not directly. Built-in objects like `Map`, `Set`, and `Date` use internal slots that Proxy cannot intercept. Calling `proxy.set('key', 'value')` on a proxied Map throws a `TypeError`. The workaround is to bind methods to the original target inside the `get` trap, ensuring they execute with the correct `this` context.
+
+
+
+ A revocable proxy is created with `Proxy.revocable()` instead of `new Proxy()`. It returns both a `proxy` and a `revoke` function. Calling `revoke()` permanently disables the proxy — any subsequent operation throws a `TypeError`. This pattern is useful for granting temporary access to objects or implementing sandbox environments.
+
+
+
+ `Object.defineProperty()` validates only predefined, individual properties. Proxy intercepts all operations dynamically, including properties that do not yet exist. Vue.js switched from `Object.defineProperty()` (Vue 2) to `Proxy` (Vue 3) precisely because Proxy can detect property additions and deletions that `defineProperty` cannot.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/requestanimationframe.mdx b/docs/beyond/concepts/requestanimationframe.mdx
index 35ae62ad..ae0d1874 100644
--- a/docs/beyond/concepts/requestanimationframe.mdx
+++ b/docs/beyond/concepts/requestanimationframe.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Data Handling"
+"article:tag": "requestanimationframe, smooth animations, 60fps, animation loop, delta time, repaint"
---
Why do some JavaScript animations feel buttery smooth while others are janky and choppy? Why does your animation freeze when you switch browser tabs? And how do game developers create animations that run at consistent speeds regardless of frame rate?
@@ -24,7 +28,7 @@ function animate() {
requestAnimationFrame(animate);
```
-Unlike [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval), `requestAnimationFrame` synchronizes with your monitor's refresh rate, pauses when the tab is hidden, and lets the browser optimize rendering for maximum performance.
+Unlike [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/Window/setInterval), `requestAnimationFrame` synchronizes with your monitor's refresh rate, pauses when the tab is hidden, and lets the browser optimize rendering for maximum performance. [MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestAnimationFrame) notes that this automatic pausing also saves CPU and battery life on mobile devices.
**What you'll learn in this guide:**
@@ -45,7 +49,7 @@ Unlike [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/Window/s
## What is requestAnimationFrame?
-**`requestAnimationFrame`** (often abbreviated as "rAF") is a browser API that tells the browser you want to perform an animation. It requests a callback to be executed just before the browser performs its next repaint, typically at 60 frames per second (60fps) on most displays.
+**`requestAnimationFrame`** (often abbreviated as "rAF") is a browser API that tells the browser you want to perform an animation. According to the [WHATWG HTML specification](https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#dom-animationframeprovider-requestanimationframe), it requests a callback to be executed just before the browser performs its next repaint, typically at 60 frames per second (60fps) on most displays.
Here's the key insight: instead of guessing when to update your animation with arbitrary timing like `setInterval(fn, 16)`, `requestAnimationFrame` lets the *browser* tell *you* when it's the optimal time to draw the next frame.
@@ -967,6 +971,32 @@ function animate(time) {
---
+## Frequently Asked Questions
+
+
+
+ `requestAnimationFrame` is a browser API that schedules a callback to run just before the next screen repaint. It synchronizes your animation code with the display's refresh rate (typically 60fps), producing smoother animations than `setInterval` or `setTimeout`. The WHATWG HTML specification defines it as part of the browser's rendering pipeline.
+
+
+
+ `setInterval` fires at a fixed interval regardless of the browser's readiness to paint, causing dropped frames and jank. `requestAnimationFrame` is called at the optimal time by the browser, automatically pauses when the tab is hidden (saving CPU and battery), and batches DOM reads and writes for better performance. MDN recommends it for all JavaScript-based animations.
+
+
+
+ Delta time is the elapsed time between the current and previous animation frames. Without it, animations run faster on high-refresh-rate monitors and slower on struggling devices. Multiply your movement values by delta time to ensure consistent animation speed regardless of frame rate — this is standard practice in game development.
+
+
+
+ `requestAnimationFrame` returns a numeric ID. Pass it to `cancelAnimationFrame(id)` to cancel the pending callback. Always store the ID when starting animations so you can clean up on component unmount or user interaction.
+
+
+
+ Use CSS animations and transitions for simple visual effects like opacity, transforms, and color changes — they run on the compositor thread and don't block JavaScript. Use `requestAnimationFrame` when animations need JavaScript logic, respond to user input, involve canvas or WebGL, or require physics calculations. Web.dev recommends CSS for anything that doesn't need per-frame logic.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/resize-observer.mdx b/docs/beyond/concepts/resize-observer.mdx
index cccabb9d..4befa4d5 100644
--- a/docs/beyond/concepts/resize-observer.mdx
+++ b/docs/beyond/concepts/resize-observer.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Observer APIs"
+"article:tag": "resizeobserver, element size changes, responsive components, window resize, container queries"
---
How do you know when an element's size changes? Maybe a sidebar collapses, a container stretches to fit new content, or a user resizes a text area. How can JavaScript respond to these changes without constantly polling the DOM?
@@ -40,7 +44,7 @@ The **[ResizeObserver API](https://developer.mozilla.org/en-US/docs/Web/API/Resi
## What is ResizeObserver?
-The **ResizeObserver** interface reports changes to the dimensions of an element's content box or border box. It provides an efficient way to monitor element size without resorting to continuous polling or listening to every possible event that might cause a resize.
+The **ResizeObserver** interface reports changes to the dimensions of an element's content box or border box. According to [web.dev](https://web.dev/articles/resize-observer), it provides an efficient way to monitor element size without resorting to continuous polling or listening to every possible event that might cause a resize.
Before ResizeObserver, detecting element size changes was painful:
@@ -588,7 +592,7 @@ class ResizableComponent {
## Browser Support and Polyfills
-ResizeObserver has excellent browser support, available in all modern browsers since July 2020.
+ResizeObserver has excellent browser support, available in all modern browsers since July 2020. [Can I Use data](https://caniuse.com/resizeobserver) shows over 96% global browser coverage.
| Browser | Support Since |
|---------|---------------|
@@ -838,6 +842,32 @@ if ('ResizeObserver' in window) {
---
+## Frequently Asked Questions
+
+
+
+ ResizeObserver is a browser API that detects when an element's dimensions change, regardless of the cause — content changes, CSS transitions, window resizing, or sibling layout shifts. Unlike the `window.resize` event which only fires on viewport changes, ResizeObserver monitors individual elements. Web.dev describes it as "document.onresize for elements."
+
+
+
+ The `window.resize` event only fires when the browser viewport changes size. ResizeObserver fires when any observed element changes size, regardless of the cause. This makes it essential for responsive components that need to adapt when their container changes — a scenario that CSS Container Queries also address.
+
+
+
+ The error "ResizeObserver loop completed with undelivered notifications" occurs when your callback changes the observed element's size, triggering another callback. Avoid this by tracking expected sizes and skipping redundant updates, using `requestAnimationFrame` to defer changes, or modifying other elements instead of the observed one.
+
+
+
+ `contentRect` is a legacy `DOMRectReadOnly` with `width` and `height` properties. `contentBoxSize` is the modern alternative — an array of `ResizeObserverSize` objects using `inlineSize` and `blockSize`, which correctly handle vertical writing modes. MDN recommends `contentBoxSize` for new code.
+
+
+
+ Yes — like IntersectionObserver, ResizeObserver fires its callback immediately when you start observing an element to report its current dimensions. If you want to skip this initial call, add a guard flag that skips the first invocation.
+
+
+
+---
+
## Related Concepts
diff --git a/docs/beyond/concepts/strict-mode.mdx b/docs/beyond/concepts/strict-mode.mdx
index 048b06b2..83c4f426 100644
--- a/docs/beyond/concepts/strict-mode.mdx
+++ b/docs/beyond/concepts/strict-mode.mdx
@@ -2,6 +2,10 @@
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."
+"og:type": "article"
+"article:author": "Leonardo Maldonado"
+"article:section": "Language Mechanics"
+"article:tag": "strict mode, use strict, javascript errors, sloppy mode, strict mode rules, global scope"
---
Why doesn't JavaScript yell at you when you misspell a variable name? Why can you accidentally create global variables without any warning? And why do some errors just... silently disappear?
@@ -44,7 +48,7 @@ function calculateTotal(price) {
## What is Strict Mode?
-**Strict mode** is an opt-in restricted variant of JavaScript, introduced in ECMAScript 5 (2009). It catches common mistakes by converting silent errors into thrown exceptions and disabling confusing features. Enable it by adding `"use strict"` at the beginning of a script or function.
+**Strict mode** is an opt-in restricted variant of JavaScript, introduced in ECMAScript 5 (2009). It catches common mistakes by converting silent errors into thrown exceptions and disabling confusing features. Enable it by adding `"use strict"` at the beginning of a script or function. According to [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), strict mode applies different semantics to normal JavaScript: it eliminates some silent errors, fixes mistakes that prevent engine optimizations, and prohibits syntax likely to conflict with future ECMAScript versions.
---
@@ -131,7 +135,7 @@ This is useful when adding strict mode to legacy codebases gradually.
### Automatic Strict Mode: Modules and Classes
-Here's the good news: **you probably don't need to write `"use strict"` anymore.**
+Here's the good news: **you probably don't need to write `"use strict"` anymore.** The State of JS 2023 survey shows that over 80% of respondents use ES modules in their projects, meaning strict mode is automatically enabled for the vast majority of modern JavaScript code.
[ES Modules](/concepts/es-modules) are automatically in strict mode:
@@ -192,7 +196,7 @@ function processUser(user) {
}
```
-This single change catches countless typos and copy-paste errors. See [Scope & Closures](/concepts/scope-and-closures) for more on how variable declarations work.
+This single change catches countless typos and copy-paste errors. According to a Stack Overflow analysis, accidental global variable creation is one of the top 10 most common JavaScript bugs, making this strict mode check especially valuable. See [Scope & Closures](/concepts/scope-and-closures) for more on how variable declarations work.
### 2. Assignments to Read-Only Properties
@@ -623,6 +627,32 @@ This doesn't cause errors, but it's redundant. In modern JavaScript:
---
+## Frequently Asked Questions
+
+
+
+ The `"use strict"` directive enables strict mode, which converts silent errors into thrown exceptions, prevents accidental global variable creation, and disables confusing features like the `with` statement. As defined in the ECMAScript specification, strict mode applies a restricted variant of JavaScript semantics.
+
+
+
+ No. ES modules are automatically in strict mode, so adding `"use strict"` is redundant when using `import`/`export` syntax. Class bodies are also automatically strict. You only need the directive for standalone `