From 22dfd4664028a490c89054f033463cab9864dc7a Mon Sep 17 00:00:00 2001 From: Leonardo Maldonado Date: Tue, 17 Feb 2026 10:05:49 +0100 Subject: [PATCH 1/5] fix(seo): correct OG image URL, fix homepage title, and add AI-friendly robots.txt - Change og:image to absolute URL (https://33jsconcepts.com/og-image.png) - Add thumbnails config and article:author to docs.json - Fix homepage title from '33 JavaScript Concepts' to 'Learn JavaScript' to prevent duplication - Create robots.txt allowing AI search engine bots (GPTBot, ClaudeBot, PerplexityBot) --- docs/docs.json | 6 +++++- docs/index.mdx | 2 +- docs/robots.txt | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 docs/robots.txt diff --git a/docs/docs.json b/docs/docs.json index 8a60f6f1..5998b416 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -13,17 +13,21 @@ "dark": "#C9B83C" }, "favicon": "/favicon.ico", + "thumbnails": { + "appearance": "dark" + }, "seo": { "indexing": "navigable", "metatags": { "og:type": "website", "og:site_name": "33 JavaScript Concepts", "og:locale": "en_US", - "og:image": "/og-image.png", + "og:image": "https://33jsconcepts.com/og-image.png", "twitter:card": "summary_large_image", "twitter:site": "@leonardomso", "twitter:creator": "@leonardomso", "twitter:image": "/og-image.png", + "article:author": "Leonardo Maldonado", "author": "Leonardo Maldonado", "keywords": "JavaScript, JS, learn JavaScript, JavaScript tutorial, JavaScript concepts, JavaScript fundamentals, web development, programming, coding, closures, promises, async await, event loop, DOM, prototypes", "language": "en", diff --git a/docs/index.mdx b/docs/index.mdx index 27be5e54..bb2512ac 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -1,5 +1,5 @@ --- -title: "33 JavaScript Concepts" +title: "Learn JavaScript" sidebarTitle: "Welcome" description: "Master JavaScript with 33 core concepts. Clear explanations, practical examples, and curated resources for developers at any level." --- diff --git a/docs/robots.txt b/docs/robots.txt new file mode 100644 index 00000000..4dd51365 --- /dev/null +++ b/docs/robots.txt @@ -0,0 +1,53 @@ +# Belt-and-suspenders robots.txt for 33jsconcepts.com +# +# PRIMARY FIX: Cloudflare dashboard configuration is required to override +# Cloudflare-managed AI bot blocking. This file serves as the origin-level +# directive and fallback if Cloudflare managed robots is disabled. +# +# Cloudflare Dashboard Paths: +# - Security -> Settings -> Bot traffic -> robots.txt setting +# - AI Crawl Control -> Crawlers (allow/block per crawler) +# - AI Crawl Control -> Robots.txt tab (check managed status) +# +# This file allows ALL major search engines and AI crawlers to index content. + +# Default rule: Allow all bots to crawl everything except Cloudflare internal paths +User-agent: * +Allow: / +Disallow: /cdn-cgi/ + +# Explicit allow directives for major search engine bots +User-agent: Googlebot +Allow: / + +User-agent: Bingbot +Allow: / + +User-agent: Yandexbot +Allow: / + +User-agent: DuckDuckBot +Allow: / + +# Explicit allow directives for AI search engine bots +# These override any Cloudflare-managed blocks at the origin level +User-agent: GPTBot +Allow: / + +User-agent: ChatGPT-User +Allow: / + +User-agent: ClaudeBot +Allow: / + +User-agent: anthropic-ai +Allow: / + +User-agent: PerplexityBot +Allow: / + +User-agent: Google-Extended +Allow: / + +# Sitemap for search engine discovery +Sitemap: https://33jsconcepts.com/sitemap.xml From 3f1bb09428ce209ff851faad23540869a26de76d Mon Sep 17 00:00:00 2001 From: Leonardo Maldonado Date: Tue, 17 Feb 2026 10:05:56 +0100 Subject: [PATCH 2/5] feat(seo): add JSON-LD structured data injection and FAQ section prototype - Create schema-inject.js for dynamic JSON-LD (TechArticle, FAQPage, BreadcrumbList, WebSite) - Add SEO frontmatter to scope-and-closures page (og:type, article:author, article:tag) - Add FAQ section with 6 search-optimized questions for GEO visibility - Script runs on all pages, detects page type from URL, extracts data from DOM --- docs/concepts/scope-and-closures.mdx | 44 ++++- docs/schema-inject.js | 252 +++++++++++++++++++++++++++ 2 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 docs/schema-inject.js diff --git a/docs/concepts/scope-and-closures.mdx b/docs/concepts/scope-and-closures.mdx index 455a5311..defe3e29 100644 --- a/docs/concepts/scope-and-closures.mdx +++ b/docs/concepts/scope-and-closures.mdx @@ -1,7 +1,11 @@ --- title: "Scope & Closures" sidebarTitle: "Scope and Closures: How Variables Really Work" -description: "Learn JavaScript scope and closures. Understand var vs let vs const, lexical scoping, the scope chain, and closure patterns." +description: "Learn JavaScript scope and closures. Understand the three types of scope, var vs let vs const, lexical scoping, the scope chain, and closure patterns for data privacy." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "JavaScript Fundamentals" +"article:tag": "javascript closures, javascript scope, var let const, lexical scope, scope chain, closure patterns" --- Why can some variables be accessed from anywhere in your code, while others seem to disappear? How do functions "remember" variables from their parent functions, even after those functions have finished running? @@ -1082,6 +1086,44 @@ cleanup(); // Removes listener, allows memory to be freed --- +## Frequently Asked Questions + + + + Scope defines where a variable can be accessed in your code. A closure is what happens when a function keeps access to variables from its outer lexical scope even after that outer function returns. In short: scope is the rulebook, closure is a practical behavior created by those rules. + + + + `let` and `const` are block-scoped, so they reduce accidental leaks and make intent clearer. `const` communicates that the binding should not be reassigned, while `let` is for values that change. `var` is function-scoped and hoisted in ways that often produce bugs, especially inside loops and conditionals. + + + + A function closes over the variables available where it was defined, not where it is called. When that function runs later, JavaScript still resolves those captured variables through the saved lexical environment. + + ```javascript + function makeGreeter(name) { + return function greet() { + return `Hi, ${name}`; + }; + } + ``` + + + + Common uses include data privacy, function factories, memoization, and stateful callbacks. As Kyle Simpson explains in *You Don't Know JS: Scope & Closures*, closures are not a niche feature; they are a core part of how JavaScript functions work. You will use closures any time a callback needs to remember context. + + + + JavaScript uses lexical scope, which means variable access is decided by where code is written in the file. Dynamic scope would decide variable access based on the call stack at runtime, but JavaScript does not use that model. This is why moving a function changes what it can access, even if calls stay the same. + + + + Closures can keep objects in memory longer than expected if they retain references you no longer need. This is most common with long-lived event listeners and timers that capture large data structures. In the 2023 State of JS survey, many developers still reported debugging memory/performance issues, so cleaning up listeners and limiting captured data is an important habit. + + + +--- + ## Related Concepts diff --git a/docs/schema-inject.js b/docs/schema-inject.js new file mode 100644 index 00000000..7092f5c5 --- /dev/null +++ b/docs/schema-inject.js @@ -0,0 +1,252 @@ +(function () { + var SITE_NAME = "33 JavaScript Concepts"; + var SITE_URL = "https://33jsconcepts.com"; + var AUTHOR = { + "@type": "Person", + name: "Leonardo Maldonado", + url: "https://github.com/leonardomso", + }; + var PUBLISHER = { + "@type": "Organization", + name: SITE_NAME, + url: SITE_URL, + }; + + function safeText(value) { + return (value || "").replace(/\s+/g, " ").trim(); + } + + function toTitle(segment) { + var cleaned = decodeURIComponent(segment || "").replace(/[-_]+/g, " ").trim(); + if (!cleaned) return ""; + return cleaned + .split(" ") + .map(function (word) { + return word.charAt(0).toUpperCase() + word.slice(1); + }) + .join(" "); + } + + function getCanonicalUrl() { + var canonical = document.querySelector('link[rel="canonical"]'); + if (canonical && canonical.href) return canonical.href; + return new URL(window.location.pathname + window.location.search, SITE_URL).toString(); + } + + function getDescription() { + var meta = document.querySelector('meta[name="description"]'); + return safeText(meta && meta.content); + } + + function getDatePublished() { + var publishedMeta = document.querySelector('meta[property="article:published_time"]'); + if (publishedMeta && publishedMeta.content) return publishedMeta.content; + + var timeEl = document.querySelector("time[datetime]"); + if (timeEl) { + var dateTime = timeEl.getAttribute("datetime"); + if (dateTime) return dateTime; + } + + if (document.lastModified) { + var parsed = new Date(document.lastModified); + if (!Number.isNaN(parsed.getTime())) return parsed.toISOString(); + } + + return new Date().toISOString(); + } + + function isConceptArticle(pathname) { + return /^\/(concepts|beyond\/concepts)\/.+/.test(pathname); + } + + function buildBreadcrumbList(pathname) { + var parts = pathname.split("/").filter(Boolean); + var itemListElement = [ + { + "@type": "ListItem", + position: 1, + name: "Home", + item: SITE_URL + "/", + }, + ]; + + var runningPath = ""; + for (var i = 0; i < parts.length; i += 1) { + runningPath += "/" + parts[i]; + itemListElement.push({ + "@type": "ListItem", + position: i + 2, + name: toTitle(parts[i]), + item: SITE_URL + runningPath, + }); + } + + return { + "@type": "BreadcrumbList", + itemListElement: itemListElement, + }; + } + + function findFaqHeading() { + var headings = Array.prototype.slice.call(document.querySelectorAll("h2")); + return ( + headings.find(function (heading) { + return safeText(heading.textContent).toLowerCase().indexOf("frequently asked questions") !== -1; + }) || null + ); + } + + function getFaqSectionNodes(heading) { + var nodes = []; + var cursor = heading ? heading.nextElementSibling : null; + while (cursor) { + if (cursor.tagName === "H2") break; + nodes.push(cursor); + cursor = cursor.nextElementSibling; + } + return nodes; + } + + function extractFaqItems() { + var heading = findFaqHeading(); + if (!heading) return []; + + var sectionNodes = getFaqSectionNodes(heading); + if (!sectionNodes.length) return []; + + var questions = []; + var seen = new Set(); + var triggerSelector = [ + "button", + "summary", + "[role='button']", + "[aria-controls]", + "[data-state]", + ].join(","); + + sectionNodes.forEach(function (node) { + var triggers = Array.prototype.slice.call(node.querySelectorAll(triggerSelector)); + + triggers.forEach(function (trigger) { + var questionText = safeText(trigger.textContent); + if (!questionText || questionText.length < 10) return; + if (seen.has(questionText)) return; + + var answerText = ""; + var controlsId = trigger.getAttribute("aria-controls"); + if (controlsId) { + var controlled = document.getElementById(controlsId); + answerText = safeText(controlled && controlled.textContent); + } + + if (!answerText) { + var itemRoot = trigger.closest("[data-radix-collection-item], details, li, div"); + if (itemRoot) { + var answerCandidate = Array.prototype.slice + .call(itemRoot.querySelectorAll("p, div")) + .map(function (el) { + if (el === trigger || el.contains(trigger)) return ""; + return safeText(el.textContent); + }) + .find(function (text) { + return text && text.length > 20; + }); + answerText = answerCandidate || ""; + } + } + + if (!answerText) return; + + seen.add(questionText); + questions.push({ + "@type": "Question", + name: questionText, + acceptedAnswer: { + "@type": "Answer", + text: answerText, + }, + }); + }); + }); + + return questions; + } + + function buildGraph() { + var pathname = window.location.pathname || "/"; + var headline = safeText(document.title); + var description = getDescription(); + var canonicalUrl = getCanonicalUrl(); + var graph = []; + + if (pathname === "/") { + graph.push({ + "@type": "WebSite", + name: SITE_NAME, + description: description, + url: SITE_URL, + potentialAction: { + "@type": "SearchAction", + target: SITE_URL + "/search?q={search_term_string}", + "query-input": "required name=search_term_string", + }, + }); + } else if (isConceptArticle(pathname)) { + graph.push({ + "@type": "TechArticle", + headline: headline, + description: description, + author: AUTHOR, + publisher: PUBLISHER, + datePublished: getDatePublished(), + url: canonicalUrl, + mainEntityOfPage: canonicalUrl, + }); + } else { + graph.push({ + "@type": "WebPage", + name: headline, + description: description, + url: canonicalUrl, + }); + } + + graph.push(buildBreadcrumbList(pathname)); + + var faqItems = extractFaqItems(); + if (faqItems.length) { + graph.push({ + "@type": "FAQPage", + mainEntity: faqItems, + }); + } + + return graph; + } + + function injectSchema() { + try { + var graph = buildGraph(); + if (!graph.length) return; + + var existing = document.getElementById("structured-data-jsonld"); + if (existing) existing.remove(); + + var script = document.createElement("script"); + script.id = "structured-data-jsonld"; + script.type = "application/ld+json"; + script.text = JSON.stringify({ + "@context": "https://schema.org", + "@graph": graph, + }); + document.head.appendChild(script); + } catch (_error) {} + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", injectSchema); + } else { + injectSchema(); + } +})(); From 3bfd4b1ba805ea179d0e8fbb4685698b8c309cb4 Mon Sep 17 00:00:00 2001 From: Leonardo Maldonado Date: Tue, 17 Feb 2026 10:17:01 +0100 Subject: [PATCH 3/5] feat(seo): add per-page SEO metadata to all 70 pages Add og:type, article:author, article:section, and article:tag frontmatter fields to all documentation pages for improved search engine optimization and social media sharing. --- docs/beyond/concepts/blob-file-api.mdx | 4 ++++ docs/beyond/concepts/computed-property-names.mdx | 4 ++++ docs/beyond/concepts/cookies.mdx | 4 ++++ docs/beyond/concepts/custom-events.mdx | 4 ++++ docs/beyond/concepts/debouncing-throttling.mdx | 4 ++++ docs/beyond/concepts/event-bubbling-capturing.mdx | 4 ++++ docs/beyond/concepts/event-delegation.mdx | 4 ++++ docs/beyond/concepts/garbage-collection.mdx | 4 ++++ docs/beyond/concepts/getters-setters.mdx | 4 ++++ docs/beyond/concepts/hoisting.mdx | 4 ++++ docs/beyond/concepts/indexeddb.mdx | 4 ++++ docs/beyond/concepts/intersection-observer.mdx | 4 ++++ docs/beyond/concepts/javascript-type-nuances.mdx | 4 ++++ docs/beyond/concepts/json-deep-dive.mdx | 4 ++++ docs/beyond/concepts/localstorage-sessionstorage.mdx | 4 ++++ docs/beyond/concepts/memoization.mdx | 4 ++++ docs/beyond/concepts/memory-management.mdx | 4 ++++ docs/beyond/concepts/mutation-observer.mdx | 4 ++++ docs/beyond/concepts/object-methods.mdx | 4 ++++ docs/beyond/concepts/performance-observer.mdx | 4 ++++ docs/beyond/concepts/property-descriptors.mdx | 4 ++++ docs/beyond/concepts/proxy-reflect.mdx | 4 ++++ docs/beyond/concepts/requestanimationframe.mdx | 4 ++++ docs/beyond/concepts/resize-observer.mdx | 4 ++++ docs/beyond/concepts/strict-mode.mdx | 4 ++++ docs/beyond/concepts/tagged-template-literals.mdx | 4 ++++ docs/beyond/concepts/temporal-dead-zone.mdx | 4 ++++ docs/beyond/concepts/typed-arrays-arraybuffers.mdx | 4 ++++ docs/beyond/concepts/weakmap-weakset.mdx | 4 ++++ docs/beyond/getting-started/overview.mdx | 4 ++++ docs/concepts/algorithms-big-o.mdx | 4 ++++ docs/concepts/async-await.mdx | 4 ++++ docs/concepts/call-stack.mdx | 4 ++++ docs/concepts/callbacks.mdx | 4 ++++ docs/concepts/clean-code.mdx | 4 ++++ docs/concepts/currying-composition.mdx | 4 ++++ docs/concepts/data-structures.mdx | 4 ++++ docs/concepts/design-patterns.mdx | 4 ++++ docs/concepts/dom.mdx | 4 ++++ docs/concepts/equality-operators.mdx | 4 ++++ docs/concepts/error-handling.mdx | 4 ++++ docs/concepts/es-modules.mdx | 4 ++++ docs/concepts/event-loop.mdx | 4 ++++ docs/concepts/factories-classes.mdx | 4 ++++ docs/concepts/generators-iterators.mdx | 4 ++++ docs/concepts/higher-order-functions.mdx | 4 ++++ docs/concepts/http-fetch.mdx | 4 ++++ docs/concepts/iife-modules.mdx | 4 ++++ docs/concepts/inheritance-polymorphism.mdx | 4 ++++ docs/concepts/javascript-engines.mdx | 4 ++++ docs/concepts/map-reduce-filter.mdx | 4 ++++ docs/concepts/modern-js-syntax.mdx | 4 ++++ docs/concepts/object-creation-prototypes.mdx | 4 ++++ docs/concepts/primitive-types.mdx | 4 ++++ docs/concepts/primitives-objects.mdx | 4 ++++ docs/concepts/promises.mdx | 4 ++++ docs/concepts/pure-functions.mdx | 4 ++++ docs/concepts/recursion.mdx | 4 ++++ docs/concepts/regular-expressions.mdx | 4 ++++ docs/concepts/this-call-apply-bind.mdx | 4 ++++ docs/concepts/type-coercion.mdx | 4 ++++ docs/concepts/web-workers.mdx | 4 ++++ docs/contributing.mdx | 4 ++++ docs/getting-started/about.mdx | 4 ++++ docs/getting-started/how-to-learn.mdx | 4 ++++ docs/getting-started/learning-paths.mdx | 4 ++++ docs/getting-started/prerequisites.mdx | 4 ++++ docs/index.mdx | 1 + docs/translations.mdx | 4 ++++ 69 files changed, 273 insertions(+) diff --git a/docs/beyond/concepts/blob-file-api.mdx b/docs/beyond/concepts/blob-file-api.mdx index 12ade561..e29d845a 100644 --- a/docs/beyond/concepts/blob-file-api.mdx +++ b/docs/beyond/concepts/blob-file-api.mdx @@ -2,6 +2,10 @@ title: "Blob & File API in JavaScript" sidebarTitle: "Blob & File API" description: "Learn JavaScript Blob and File APIs for binary data. Create, read, and manipulate files, handle uploads, generate downloads, and work with FileReader." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Data Handling" +"article:tag": "blob file api, file upload, filereader, binary data, file download, file handling" --- How do you let users upload images? How do you create a downloadable file from data generated in JavaScript? How can you read the contents of a file the user selected? diff --git a/docs/beyond/concepts/computed-property-names.mdx b/docs/beyond/concepts/computed-property-names.mdx index bd61692d..332e2435 100644 --- a/docs/beyond/concepts/computed-property-names.mdx +++ b/docs/beyond/concepts/computed-property-names.mdx @@ -2,6 +2,10 @@ title: "Computed Property Names in JS" sidebarTitle: "Computed Property Names" description: "Learn JavaScript computed property names. Create dynamic object keys with variables, expressions, Symbols, and computed methods for cleaner ES6+ code." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Modern Syntax & Operators" +"article:tag": "computed property names, dynamic object keys, es6 syntax, bracket notation, symbols" --- Have you ever needed to create an object where the property name comes from a variable? Before ES6, this required creating the object first, then adding the property in a separate step. Computed property names changed everything. diff --git a/docs/beyond/concepts/cookies.mdx b/docs/beyond/concepts/cookies.mdx index e3e5126d..605227c4 100644 --- a/docs/beyond/concepts/cookies.mdx +++ b/docs/beyond/concepts/cookies.mdx @@ -2,6 +2,10 @@ title: "Cookies in JavaScript" sidebarTitle: "Cookies" description: "Learn JavaScript cookies. Understand how to read, write, and delete cookies, cookie attributes like HttpOnly and SameSite, and security best practices." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Browser Storage" +"article:tag": "cookies, http cookies, cookie attributes, httponly samesite, cookie security" --- Why do websites "remember" you're logged in, even after closing your browser? How does that shopping cart persist across tabs? Why can some data survive for weeks while other data vanishes when you close a tab? diff --git a/docs/beyond/concepts/custom-events.mdx b/docs/beyond/concepts/custom-events.mdx index 90fe0af8..052186cc 100644 --- a/docs/beyond/concepts/custom-events.mdx +++ b/docs/beyond/concepts/custom-events.mdx @@ -2,6 +2,10 @@ title: "Custom Events in JavaScript" sidebarTitle: "Custom Events" description: "Learn JavaScript custom events. Create and dispatch CustomEvent, pass data with detail, and build event-driven architectures." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Events" +"article:tag": "custom events, customevent, event dispatch, event-driven architecture, event detail" --- What if you could create your own events, just like `click` or `submit`? What if a shopping cart could announce "item added!" and any part of your app could listen and respond? How do you build components that communicate without knowing about each other? diff --git a/docs/beyond/concepts/debouncing-throttling.mdx b/docs/beyond/concepts/debouncing-throttling.mdx index 1b67405e..695f2c71 100644 --- a/docs/beyond/concepts/debouncing-throttling.mdx +++ b/docs/beyond/concepts/debouncing-throttling.mdx @@ -2,6 +2,10 @@ title: "Debouncing & Throttling in JS" sidebarTitle: "Debouncing & Throttling: Control Event Frequency" description: "Learn debouncing and throttling in JavaScript. Optimize event handlers, reduce API calls, and implement both patterns from scratch with real-world examples." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Memory & Performance" +"article:tag": "debouncing throttling, event optimization, api calls, performance patterns, event handlers" --- What happens when a user types in a search box at 60 characters per minute? Or when they scroll through your page, triggering hundreds of events per second? Without proper handling, your application can grind to a halt, making unnecessary API calls or blocking the main thread with expensive computations. diff --git a/docs/beyond/concepts/event-bubbling-capturing.mdx b/docs/beyond/concepts/event-bubbling-capturing.mdx index 9d798555..0b2ff142 100644 --- a/docs/beyond/concepts/event-bubbling-capturing.mdx +++ b/docs/beyond/concepts/event-bubbling-capturing.mdx @@ -2,6 +2,10 @@ title: "Event Bubbling & Capturing" sidebarTitle: "Event Bubbling & Capturing" description: "Learn event bubbling and capturing in JavaScript. Understand the three phases of event propagation, stopPropagation, and when to use capturing vs bubbling." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Events" +"article:tag": "event bubbling, event capturing, event propagation, stoppropagation, dom events" --- You click a button inside a `
`, 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? diff --git a/docs/beyond/concepts/event-delegation.mdx b/docs/beyond/concepts/event-delegation.mdx index b7e59c6d..175620f7 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. diff --git a/docs/beyond/concepts/garbage-collection.mdx b/docs/beyond/concepts/garbage-collection.mdx index fc8be733..56aacf45 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? diff --git a/docs/beyond/concepts/getters-setters.mdx b/docs/beyond/concepts/getters-setters.mdx index 0123879d..875571a1 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? diff --git a/docs/beyond/concepts/hoisting.mdx b/docs/beyond/concepts/hoisting.mdx index 5798a96d..cce9973a 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? diff --git a/docs/beyond/concepts/indexeddb.mdx b/docs/beyond/concepts/indexeddb.mdx index 5bedc9b4..6cdc6c56 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? diff --git a/docs/beyond/concepts/intersection-observer.mdx b/docs/beyond/concepts/intersection-observer.mdx index f66ffb52..55e9fd43 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? diff --git a/docs/beyond/concepts/javascript-type-nuances.mdx b/docs/beyond/concepts/javascript-type-nuances.mdx index 16e8f440..00666683 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? diff --git a/docs/beyond/concepts/json-deep-dive.mdx b/docs/beyond/concepts/json-deep-dive.mdx index a0b2ed9b..92533292 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? diff --git a/docs/beyond/concepts/localstorage-sessionstorage.mdx b/docs/beyond/concepts/localstorage-sessionstorage.mdx index 009dc6b3..f1e26eb2 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? diff --git a/docs/beyond/concepts/memoization.mdx b/docs/beyond/concepts/memoization.mdx index e359a754..a26c7e9e 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? diff --git a/docs/beyond/concepts/memory-management.mdx b/docs/beyond/concepts/memory-management.mdx index 44600e5d..5008b919 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. diff --git a/docs/beyond/concepts/mutation-observer.mdx b/docs/beyond/concepts/mutation-observer.mdx index 8b86d43c..f69c4145 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? diff --git a/docs/beyond/concepts/object-methods.mdx b/docs/beyond/concepts/object-methods.mdx index 6e9a7f1f..8535ce69 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? diff --git a/docs/beyond/concepts/performance-observer.mdx b/docs/beyond/concepts/performance-observer.mdx index da4592b1..f6691538 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. diff --git a/docs/beyond/concepts/property-descriptors.mdx b/docs/beyond/concepts/property-descriptors.mdx index ba62aa05..96cac599 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? diff --git a/docs/beyond/concepts/proxy-reflect.mdx b/docs/beyond/concepts/proxy-reflect.mdx index c5f62ee4..05e06c4f 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? diff --git a/docs/beyond/concepts/requestanimationframe.mdx b/docs/beyond/concepts/requestanimationframe.mdx index 35ae62ad..ea37eb25 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? diff --git a/docs/beyond/concepts/resize-observer.mdx b/docs/beyond/concepts/resize-observer.mdx index cccabb9d..0f8f7ff8 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? diff --git a/docs/beyond/concepts/strict-mode.mdx b/docs/beyond/concepts/strict-mode.mdx index 048b06b2..b2e5d4fe 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? diff --git a/docs/beyond/concepts/tagged-template-literals.mdx b/docs/beyond/concepts/tagged-template-literals.mdx index 83a7bf44..a8573b6a 100644 --- a/docs/beyond/concepts/tagged-template-literals.mdx +++ b/docs/beyond/concepts/tagged-template-literals.mdx @@ -2,6 +2,10 @@ title: "Tagged Template Literals" sidebarTitle: "Tagged Template Literals" description: "Learn JavaScript tagged template literals. Understand tag functions, access raw strings, and build HTML sanitizers and DSLs." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Modern Syntax & Operators" +"article:tag": "tagged template literals, template strings, tag functions, dsl, html sanitizers" --- How do libraries like GraphQL and Lit HTML let you write special syntax inside JavaScript template literals? How can a function intercept and transform template strings before they become a final value? diff --git a/docs/beyond/concepts/temporal-dead-zone.mdx b/docs/beyond/concepts/temporal-dead-zone.mdx index d2765295..530ed6e0 100644 --- a/docs/beyond/concepts/temporal-dead-zone.mdx +++ b/docs/beyond/concepts/temporal-dead-zone.mdx @@ -2,6 +2,10 @@ title: "Temporal Dead Zone in JS" sidebarTitle: "Temporal Dead Zone" description: "Learn the Temporal Dead Zone (TDZ) in JavaScript. Understand why let, const, and class throw ReferenceError before initialization, and how TDZ differs from var." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Language Mechanics" +"article:tag": "temporal dead zone, let const hoisting, reference error, tdz, block scope, declaration timing" --- Why does this code throw an error? diff --git a/docs/beyond/concepts/typed-arrays-arraybuffers.mdx b/docs/beyond/concepts/typed-arrays-arraybuffers.mdx index d5417fba..19df619d 100644 --- a/docs/beyond/concepts/typed-arrays-arraybuffers.mdx +++ b/docs/beyond/concepts/typed-arrays-arraybuffers.mdx @@ -2,6 +2,10 @@ title: "Typed Arrays in JavaScript" sidebarTitle: "Typed Arrays & ArrayBuffers" description: "Learn JavaScript Typed Arrays and ArrayBuffers for binary data handling. Work with DataView, WebGL, and file processing." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Data Handling" +"article:tag": "typed arrays, arraybuffer, binary data, dataview, webgl, uint8array" --- How do you process a PNG image pixel by pixel? How do you read binary data from a WebSocket? How does WebGL render millions of triangles efficiently? diff --git a/docs/beyond/concepts/weakmap-weakset.mdx b/docs/beyond/concepts/weakmap-weakset.mdx index 0ea71bf3..3adfe924 100644 --- a/docs/beyond/concepts/weakmap-weakset.mdx +++ b/docs/beyond/concepts/weakmap-weakset.mdx @@ -2,6 +2,10 @@ title: "WeakMap & WeakSet in JavaScript" sidebarTitle: "WeakMap & WeakSet" description: "Learn JavaScript WeakMap and WeakSet. Understand weak references, automatic garbage collection, private data patterns, and when to use them over Map and Set." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Objects & Properties" +"article:tag": "weakmap weakset, weak references, garbage collection, private data, memory management" --- Why does storing objects in a Map sometimes cause memory leaks? How can you attach metadata to objects without preventing them from being garbage collected? What's the difference between "strong" and "weak" references? diff --git a/docs/beyond/getting-started/overview.mdx b/docs/beyond/getting-started/overview.mdx index bcbef876..62d21a7b 100644 --- a/docs/beyond/getting-started/overview.mdx +++ b/docs/beyond/getting-started/overview.mdx @@ -2,6 +2,10 @@ title: "Beyond 33: Extended JavaScript Concepts" sidebarTitle: "Overview" description: "Go beyond the original 33 with 29 advanced JavaScript concepts. Master hoisting, proxies, observers, and performance optimization." +"og:type": "website" +"article:author": "Leonardo Maldonado" +"article:section": "Beyond 33" +"article:tag": "advanced javascript, javascript concepts, proxies, performance optimization, metaprogramming" --- You've learned the fundamentals. Now it's time to go deeper. diff --git a/docs/concepts/algorithms-big-o.mdx b/docs/concepts/algorithms-big-o.mdx index f09d73e0..273bd115 100644 --- a/docs/concepts/algorithms-big-o.mdx +++ b/docs/concepts/algorithms-big-o.mdx @@ -2,6 +2,10 @@ title: "Algorithms & Big O" sidebarTitle: "Algorithms & Big O: Measuring Code Performance" description: "Learn Big O notation and algorithms in JavaScript. Understand time complexity, searching, sorting, and common interview patterns." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "Big O notation, time complexity, algorithms, sorting, searching, performance analysis" --- Why does one solution pass all tests instantly while another times out? Why do interviewers care so much about "time complexity"? Consider these two functions that both find if an array contains duplicates: diff --git a/docs/concepts/async-await.mdx b/docs/concepts/async-await.mdx index e2598fd5..7e223859 100644 --- a/docs/concepts/async-await.mdx +++ b/docs/concepts/async-await.mdx @@ -2,6 +2,10 @@ title: "async/await" sidebarTitle: "async/await: Writing Async Code That Looks Synchronous" description: "Learn async/await in JavaScript. Write cleaner async code with try/catch error handling, Promise.all for parallel execution, and more." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Async JavaScript" +"article:tag": "async await, async functions, try catch error handling, Promise.all, async patterns" --- Why does asynchronous code have to look so complicated? What if you could write code that fetches data from a server, waits for user input, or reads files, all while looking as clean and readable as regular synchronous code? diff --git a/docs/concepts/call-stack.mdx b/docs/concepts/call-stack.mdx index 9a40c955..495ac888 100644 --- a/docs/concepts/call-stack.mdx +++ b/docs/concepts/call-stack.mdx @@ -2,6 +2,10 @@ title: "Call Stack" sidebarTitle: "Call Stack: How Function Execution Works" description: "Learn how the JavaScript call stack works. Understand stack frames, LIFO ordering, execution contexts, and stack overflow errors." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "JavaScript Fundamentals" +"article:tag": "javascript call stack, execution context, stack overflow, LIFO, function execution, stack frame" --- How does JavaScript keep track of which function is running? When a function calls another function, how does JavaScript know where to return when that function finishes? diff --git a/docs/concepts/callbacks.mdx b/docs/concepts/callbacks.mdx index d58a03b9..4fccbc12 100644 --- a/docs/concepts/callbacks.mdx +++ b/docs/concepts/callbacks.mdx @@ -2,6 +2,10 @@ title: "Callbacks" sidebarTitle: "Callbacks: The Foundation of Async" description: "Learn JavaScript callbacks. Understand sync vs async callbacks, error-first patterns, callback hell, and why Promises were invented." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Async JavaScript" +"article:tag": "javascript callbacks, async callbacks, callback hell, error-first pattern, callback functions" --- Why doesn't JavaScript wait? When you set a timer, make a network request, or listen for a click, how does your code keep running instead of freezing until that operation completes? diff --git a/docs/concepts/clean-code.mdx b/docs/concepts/clean-code.mdx index 02f5e54f..9017cac4 100644 --- a/docs/concepts/clean-code.mdx +++ b/docs/concepts/clean-code.mdx @@ -2,6 +2,10 @@ title: "Clean Code" sidebarTitle: "Clean Code: Writing Readable JavaScript" description: "Learn clean code principles for JavaScript. Meaningful naming, small functions, DRY, and best practices for maintainable code." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "clean code, code readability, naming conventions, DRY principle, maintainable code" --- Why do some codebases feel like a maze while others read like a well-written story? What makes code easy to change versus code that makes you want to rewrite everything from scratch? diff --git a/docs/concepts/currying-composition.mdx b/docs/concepts/currying-composition.mdx index 5f14f268..57233553 100644 --- a/docs/concepts/currying-composition.mdx +++ b/docs/concepts/currying-composition.mdx @@ -2,6 +2,10 @@ title: "Currying & Composition" sidebarTitle: "Currying & Composition: Functional Patterns" description: "Learn currying and function composition in JavaScript. Build reusable functions from simple pieces using curry, compose, and pipe for cleaner, modular code." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Functional Programming" +"article:tag": "currying, function composition, pipe compose, partial application, functional patterns" --- How does `add(1)(2)(3)` even work? Why do libraries like [Lodash](https://lodash.com/) and [Ramda](https://ramdajs.com/) let you call functions in multiple ways? And what if you could build complex data transformations by snapping together tiny, single-purpose functions like LEGO blocks? diff --git a/docs/concepts/data-structures.mdx b/docs/concepts/data-structures.mdx index 89127cb8..ef494b3b 100644 --- a/docs/concepts/data-structures.mdx +++ b/docs/concepts/data-structures.mdx @@ -2,6 +2,10 @@ title: "Data Structures" sidebarTitle: "Data Structures: Organizing and Storing Data" description: "Learn JavaScript data structures: Arrays, Objects, Maps, Sets, Stacks, Queues, and Linked Lists. Know when to use each one." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "data structures, arrays, objects, maps, sets, stacks, queues, linked lists" --- Why does finding an item in an array take longer as it grows? Why can you look up an object property instantly regardless of how many properties it has? The answer lies in **data structures**. diff --git a/docs/concepts/design-patterns.mdx b/docs/concepts/design-patterns.mdx index b725799b..1cc92969 100644 --- a/docs/concepts/design-patterns.mdx +++ b/docs/concepts/design-patterns.mdx @@ -2,6 +2,10 @@ title: "Design Patterns" sidebarTitle: "Design Patterns: Reusable Solutions" description: "Learn JavaScript design patterns like Module, Singleton, Observer, Factory, Proxy, and Decorator. Understand when to use each pattern and avoid common pitfalls." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "design patterns, singleton, observer, factory, proxy, decorator, software design" --- Ever find yourself solving the same problem over and over? What if experienced developers already figured out the best solutions to these recurring challenges? diff --git a/docs/concepts/dom.mdx b/docs/concepts/dom.mdx index e544dae0..7f7ec10b 100644 --- a/docs/concepts/dom.mdx +++ b/docs/concepts/dom.mdx @@ -2,6 +2,10 @@ title: "DOM Manipulation" sidebarTitle: "DOM: How Browsers Represent Web Pages" description: "Learn the DOM in JavaScript. Select and manipulate elements, traverse nodes, handle events, and optimize rendering performance." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Web Platform" +"article:tag": "javascript DOM, document object model, DOM manipulation, querySelector, event handling, DOM traversal" --- How does JavaScript change what you see on a webpage? How do you click a button and see new content appear, or type in a form and watch suggestions pop up? How does a "dark mode" toggle instantly transform an entire page? diff --git a/docs/concepts/equality-operators.mdx b/docs/concepts/equality-operators.mdx index 56b7f2d2..5c85c13f 100644 --- a/docs/concepts/equality-operators.mdx +++ b/docs/concepts/equality-operators.mdx @@ -2,6 +2,10 @@ title: "Equality: == vs ===" sidebarTitle: "Equality Operators: == vs === Type Checking" description: "Learn JavaScript equality: == vs ===, typeof quirks, and Object.is(). Understand type coercion and why NaN !== NaN." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "JavaScript Fundamentals" +"article:tag": "javascript equality, == vs ===, strict equality, loose equality, Object.is javascript, NaN comparison" --- Why does `1 == "1"` return `true` but `1 === "1"` return `false`? Why does `typeof null` return `"object"`? And why is `NaN` the only value in JavaScript that isn't equal to itself? diff --git a/docs/concepts/error-handling.mdx b/docs/concepts/error-handling.mdx index c68a43ab..b8313102 100644 --- a/docs/concepts/error-handling.mdx +++ b/docs/concepts/error-handling.mdx @@ -2,6 +2,10 @@ title: "Error Handling" sidebarTitle: "Error Handling: Managing Errors Gracefully" description: "Learn JavaScript error handling with try/catch/finally. Understand Error types, custom errors, async error patterns, and best practices for robust code." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "error handling, try catch finally, custom errors, error types, exception handling" --- What happens when something goes wrong in your JavaScript code? How do you prevent one small error from crashing your entire application? How do you give users helpful feedback instead of a cryptic error message? diff --git a/docs/concepts/es-modules.mdx b/docs/concepts/es-modules.mdx index cb60f1d5..664c95be 100644 --- a/docs/concepts/es-modules.mdx +++ b/docs/concepts/es-modules.mdx @@ -2,6 +2,10 @@ title: "ES Modules" sidebarTitle: "ES Modules: Native Module System" description: "Learn ES Modules in JavaScript. Understand import/export, live bindings, dynamic imports, top-level await, and tree-shaking." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "ES modules, import export, dynamic imports, tree-shaking, module system" --- Why does Node.js have two different module systems? Why can bundlers remove unused code from ES Modules but not from CommonJS? And why do some imports need curly braces while others don't? diff --git a/docs/concepts/event-loop.mdx b/docs/concepts/event-loop.mdx index f32497f0..77b24c02 100644 --- a/docs/concepts/event-loop.mdx +++ b/docs/concepts/event-loop.mdx @@ -2,6 +2,10 @@ title: "Event Loop" sidebarTitle: "Event Loop: How Async Code Actually Runs" description: "Learn how the JavaScript event loop handles async code. Understand the call stack, task queue, microtasks, and why Promises always run before setTimeout()." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Functions & Execution" +"article:tag": "javascript event loop, call stack task queue, microtasks promises, setTimeout, single threaded async" --- How does JavaScript handle multiple things at once when it can only do one thing at a time? Why does this code print in a surprising order? diff --git a/docs/concepts/factories-classes.mdx b/docs/concepts/factories-classes.mdx index 50a9077b..3074f719 100644 --- a/docs/concepts/factories-classes.mdx +++ b/docs/concepts/factories-classes.mdx @@ -2,6 +2,10 @@ title: "Factories & Classes" sidebarTitle: "Factories and Classes: Creating Objects Efficiently" description: "Learn JavaScript factory functions and ES6 classes. Understand constructors, prototypes, private fields, inheritance, and when to use each pattern." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Object-Oriented JavaScript" +"article:tag": "factory functions, ES6 classes, constructors, private fields, object creation patterns" --- How do you create hundreds of similar objects without copy-pasting? How do game developers spawn thousands of enemies? How does JavaScript let you build blueprints for objects? diff --git a/docs/concepts/generators-iterators.mdx b/docs/concepts/generators-iterators.mdx index 42589829..0550bb74 100644 --- a/docs/concepts/generators-iterators.mdx +++ b/docs/concepts/generators-iterators.mdx @@ -2,6 +2,10 @@ title: "Generators & Iterators" sidebarTitle: "Generators & Iterators: Pausable Functions" description: "Learn JavaScript generators and iterators. Understand yield, lazy evaluation, infinite sequences, and async generators." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Async JavaScript" +"article:tag": "javascript generators, iterators, yield keyword, lazy evaluation, async generators" --- What if a function could pause mid-execution, return a value, and then resume right where it left off? What if you could create a sequence of values that are computed only when you ask for them — not all at once? diff --git a/docs/concepts/higher-order-functions.mdx b/docs/concepts/higher-order-functions.mdx index 493afa31..ca4b65cd 100644 --- a/docs/concepts/higher-order-functions.mdx +++ b/docs/concepts/higher-order-functions.mdx @@ -2,6 +2,10 @@ title: "Higher-Order Functions" sidebarTitle: "Higher-Order Functions: Functions That Use Functions" description: "Learn higher-order functions in JavaScript. Understand functions that accept or return other functions, create reusable abstractions, and write cleaner code." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Functional Programming" +"article:tag": "higher-order functions, functions as arguments, function composition, functional programming" --- What if you could tell a function *how* to do something, not just *what* data to work with? What if you could pass behavior itself as an argument, just like you pass numbers or strings? diff --git a/docs/concepts/http-fetch.mdx b/docs/concepts/http-fetch.mdx index ad96c36b..1649b0d4 100644 --- a/docs/concepts/http-fetch.mdx +++ b/docs/concepts/http-fetch.mdx @@ -2,6 +2,10 @@ title: "HTTP & Fetch API" sidebarTitle: "Fetch API: Making HTTP Requests the Modern Way" description: "Learn the JavaScript Fetch API for HTTP requests. Covers GET, POST, response handling, JSON parsing, and AbortController." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Web Platform" +"article:tag": "fetch API, HTTP requests, GET POST, JSON parsing, AbortController, network requests" --- How does JavaScript get data from a server? How do you load user profiles, submit forms, or fetch the latest posts from an API? The answer is the **[Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)**, JavaScript's modern way to make network requests. diff --git a/docs/concepts/iife-modules.mdx b/docs/concepts/iife-modules.mdx index c9f8c7d4..102f7999 100644 --- a/docs/concepts/iife-modules.mdx +++ b/docs/concepts/iife-modules.mdx @@ -2,6 +2,10 @@ title: "IIFE & Namespaces" sidebarTitle: "IIFE, Modules & Namespaces: Structuring Code" description: "Learn how to organize JavaScript code with IIFEs, namespaces, and ES6 modules. Understand private scope, exports, dynamic imports, and common module mistakes." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Functions & Execution" +"article:tag": "IIFE immediately invoked function expression, javascript modules, namespace pattern, ES6 modules, code organization" --- How do you prevent your JavaScript variables from conflicting with code from other files or libraries? How do modern applications organize thousands of lines of code across multiple files? diff --git a/docs/concepts/inheritance-polymorphism.mdx b/docs/concepts/inheritance-polymorphism.mdx index 1c6c2346..126b9730 100644 --- a/docs/concepts/inheritance-polymorphism.mdx +++ b/docs/concepts/inheritance-polymorphism.mdx @@ -2,6 +2,10 @@ title: "Inheritance & Polymorphism" sidebarTitle: "Inheritance & Polymorphism: OOP Principles" description: "Learn inheritance and polymorphism in JavaScript. Extend classes, use prototype chains, override methods, and master OOP patterns." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Object-Oriented JavaScript" +"article:tag": "javascript inheritance, polymorphism, class extension, method overriding, OOP patterns" --- How do game developers create hundreds of character types without copy-pasting the same code over and over? How can a Warrior, Mage, and Archer all "attack" differently but be treated the same way in battle? diff --git a/docs/concepts/javascript-engines.mdx b/docs/concepts/javascript-engines.mdx index 33924c28..61a2c671 100644 --- a/docs/concepts/javascript-engines.mdx +++ b/docs/concepts/javascript-engines.mdx @@ -2,6 +2,10 @@ title: "JavaScript Engines" sidebarTitle: "JavaScript Engines: How V8 Runs Your Code" description: "Learn how JavaScript engines work. Understand V8's parsing, JIT compilation, hidden classes, inline caching, and garbage collection." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "javascript engines, V8 engine, JIT compilation, hidden classes, garbage collection" --- What happens when you run JavaScript code? How does a browser turn `const x = 1 + 2` into something your computer actually executes? When you write a function, what transforms those characters into instructions your CPU understands? diff --git a/docs/concepts/map-reduce-filter.mdx b/docs/concepts/map-reduce-filter.mdx index d9b26c2a..12d45787 100644 --- a/docs/concepts/map-reduce-filter.mdx +++ b/docs/concepts/map-reduce-filter.mdx @@ -2,6 +2,10 @@ title: "map, reduce, filter" sidebarTitle: "map, reduce, filter" description: "Learn map, reduce, and filter in JavaScript. Transform, filter, and combine arrays without mutation. Includes method chaining and common pitfalls." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Functional Programming" +"article:tag": "map reduce filter, array methods, functional programming, array transformation, method chaining" --- How do you transform every item in an array? How do you filter out the ones you don't need? How do you combine them all into a single result? These are the three most common operations you'll perform on arrays, and JavaScript gives you three powerful methods to handle them. diff --git a/docs/concepts/modern-js-syntax.mdx b/docs/concepts/modern-js-syntax.mdx index 2c27ed40..719f14c0 100644 --- a/docs/concepts/modern-js-syntax.mdx +++ b/docs/concepts/modern-js-syntax.mdx @@ -2,6 +2,10 @@ title: "Modern JS Syntax (ES6+)" sidebarTitle: "Modern JavaScript Syntax: ES6+ Features" description: "Learn ES6+ JavaScript syntax: destructuring, spread/rest, arrow functions, optional chaining, nullish coalescing, and template literals." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "ES6 syntax, destructuring, spread operator, arrow functions, optional chaining, template literals" --- Why does JavaScript code written in 2015 look so different from code written today? How do developers write such concise, readable code without all the boilerplate? diff --git a/docs/concepts/object-creation-prototypes.mdx b/docs/concepts/object-creation-prototypes.mdx index 33c821a2..c21a9384 100644 --- a/docs/concepts/object-creation-prototypes.mdx +++ b/docs/concepts/object-creation-prototypes.mdx @@ -2,6 +2,10 @@ title: "Prototypes & Object Creation" sidebarTitle: "Object Creation & Prototypes: How Objects Inherit" description: "Learn JavaScript prototypes and object creation. Understand the prototype chain, new operator, Object.create(), and inheritance." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Object-Oriented JavaScript" +"article:tag": "javascript prototypes, prototype chain, Object.create, new operator, object inheritance" --- How does a plain JavaScript object know about methods like `.toString()` or `.hasOwnProperty()` that you never defined? How does JavaScript let objects inherit from other objects without traditional classes? diff --git a/docs/concepts/primitive-types.mdx b/docs/concepts/primitive-types.mdx index 90508499..c50e8737 100644 --- a/docs/concepts/primitive-types.mdx +++ b/docs/concepts/primitive-types.mdx @@ -2,6 +2,10 @@ title: "Primitive Types" sidebarTitle: "Primitive Types: Building Blocks of Data" description: "Learn JavaScript's 7 primitive types: string, number, bigint, boolean, undefined, null, and symbol. Understand immutability, typeof quirks, and autoboxing." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "JavaScript Fundamentals" +"article:tag": "javascript primitive types, js data types, typeof javascript, string number boolean, javascript undefined null, symbol bigint" --- What's the difference between `"hello"` and `{ text: "hello" }`? Why can you call `"hello".toUpperCase()` if strings aren't objects? And why does `typeof null` return `"object"`? diff --git a/docs/concepts/primitives-objects.mdx b/docs/concepts/primitives-objects.mdx index c7d01024..2fe96814 100644 --- a/docs/concepts/primitives-objects.mdx +++ b/docs/concepts/primitives-objects.mdx @@ -2,6 +2,10 @@ title: "Primitives vs Objects: How JavaScript Values Actually Work" sidebarTitle: "Primitives vs Objects: How Values Work" description: "Learn how JavaScript primitives and objects differ in behavior. Understand immutability, call-by-sharing semantics, why mutation works but reassignment doesn't, and how V8 actually stores values." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "JavaScript Fundamentals" +"article:tag": "javascript primitives vs objects, pass by value reference, javascript immutability, call by sharing, value types reference types" --- Have you ever wondered why changing one variable unexpectedly changes another? Why does this happen? diff --git a/docs/concepts/promises.mdx b/docs/concepts/promises.mdx index b75a7125..61c736db 100644 --- a/docs/concepts/promises.mdx +++ b/docs/concepts/promises.mdx @@ -2,6 +2,10 @@ title: "Promises" sidebarTitle: "Promises: Managing Async Operations" description: "Learn JavaScript Promises. Create, chain, and combine Promises, handle errors properly, and avoid common async pitfalls." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Async JavaScript" +"article:tag": "javascript promises, promise chaining, Promise.all, async error handling, then catch finally" --- What if you could represent a value that doesn't exist yet? What if instead of deeply nested callbacks, you could write asynchronous code that reads almost like synchronous code? diff --git a/docs/concepts/pure-functions.mdx b/docs/concepts/pure-functions.mdx index 8c143e03..78d8a763 100644 --- a/docs/concepts/pure-functions.mdx +++ b/docs/concepts/pure-functions.mdx @@ -2,6 +2,10 @@ title: "Pure Functions" sidebarTitle: "Pure Functions: Writing Predictable Code" description: "Learn pure functions in JavaScript. Understand the two rules of purity, avoid side effects, and write testable, predictable code with immutable patterns." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Functional Programming" +"article:tag": "pure functions, side effects, immutability, functional programming, predictable code" --- Why does the same function sometimes give you different results? Why is some code easy to test while other code requires elaborate setup and mocking? Why do bugs seem to appear "randomly" when your logic looks correct? diff --git a/docs/concepts/recursion.mdx b/docs/concepts/recursion.mdx index eb21db34..3887d0a6 100644 --- a/docs/concepts/recursion.mdx +++ b/docs/concepts/recursion.mdx @@ -2,6 +2,10 @@ title: "Recursion" sidebarTitle: "Recursion: Functions That Call Themselves" description: "Learn recursion in JavaScript. Understand base cases, recursive calls, the call stack, and patterns like factorial, tree traversal, and memoization." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Functional Programming" +"article:tag": "recursion, recursive functions, base case, call stack, tree traversal, memoization" --- How do you solve a problem by breaking it into smaller versions of the same problem? What if a function could call itself to chip away at a task until it's done? diff --git a/docs/concepts/regular-expressions.mdx b/docs/concepts/regular-expressions.mdx index 660b8c90..3b19d589 100644 --- a/docs/concepts/regular-expressions.mdx +++ b/docs/concepts/regular-expressions.mdx @@ -2,6 +2,10 @@ title: "Regular Expressions" sidebarTitle: "Regular Expressions: Pattern Matching" description: "Learn regular expressions in JavaScript. Pattern syntax, character classes, quantifiers, flags, and methods like test and match." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Advanced Topics" +"article:tag": "regular expressions, regex patterns, pattern matching, character classes, quantifiers" --- How do you check if an email address is valid? How do you find and replace all phone numbers in a document? How can you extract hashtags from a tweet? diff --git a/docs/concepts/this-call-apply-bind.mdx b/docs/concepts/this-call-apply-bind.mdx index a622a742..90307ff0 100644 --- a/docs/concepts/this-call-apply-bind.mdx +++ b/docs/concepts/this-call-apply-bind.mdx @@ -2,6 +2,10 @@ title: "this, call, apply & bind" sidebarTitle: "this, call, apply, and bind: How Context Works" description: "Learn JavaScript's 'this' keyword and context binding. Master the 5 binding rules, call/apply/bind methods, and arrow functions." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Object-Oriented JavaScript" +"article:tag": "javascript this keyword, call apply bind, context binding, function context, arrow functions" --- Why does `this` sometimes point to the wrong object? Why does your method work perfectly when called directly, but break when passed as a callback? And how do **[`call`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)**, **[`apply`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply)**, and **[`bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)** let you take control? diff --git a/docs/concepts/type-coercion.mdx b/docs/concepts/type-coercion.mdx index 67c81ba9..8b5d3281 100644 --- a/docs/concepts/type-coercion.mdx +++ b/docs/concepts/type-coercion.mdx @@ -2,6 +2,10 @@ title: "Type Coercion" sidebarTitle: "Type Coercion: How Values Convert Automatically" description: "Learn JavaScript type coercion. Understand how values convert to strings, numbers, and booleans, plus the 8 falsy values." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "JavaScript Fundamentals" +"article:tag": "javascript type coercion, implicit conversion, abstract equality, truthy falsy values, javascript type casting" --- Why does `"5" + 3` give you `"53"` but `"5" - 3` gives you `2`? Why does `[] == ![]` return `true`? How does JavaScript decide what type a value should be? diff --git a/docs/concepts/web-workers.mdx b/docs/concepts/web-workers.mdx index e007f8f0..7661a2ae 100644 --- a/docs/concepts/web-workers.mdx +++ b/docs/concepts/web-workers.mdx @@ -2,6 +2,10 @@ title: "Web Workers" sidebarTitle: "Web Workers: True Parallelism" description: "Learn Web Workers in JavaScript for running code in background threads. Understand postMessage, Dedicated and Shared Workers, and transferable objects." +"og:type": "article" +"article:author": "Leonardo Maldonado" +"article:section": "Web Platform" +"article:tag": "web workers, background threads, postMessage, dedicated workers, shared workers, parallel processing" --- Ever clicked a button and watched your entire page freeze? Tried to scroll while a script was running and nothing happened? diff --git a/docs/contributing.mdx b/docs/contributing.mdx index 42dfe5e8..95abc1e8 100644 --- a/docs/contributing.mdx +++ b/docs/contributing.mdx @@ -1,6 +1,10 @@ --- title: "Contributing" description: "Want to contribute to 33 JavaScript Concepts? Learn how to submit improvements, fix issues, and help other developers learn." +"og:type": "website" +"article:author": "Leonardo Maldonado" +"article:section": "Community" +"article:tag": "contribute open source, javascript community, github contributions, open source guide" --- ## Welcome Contributors! diff --git a/docs/getting-started/about.mdx b/docs/getting-started/about.mdx index b74689ed..6733c084 100644 --- a/docs/getting-started/about.mdx +++ b/docs/getting-started/about.mdx @@ -2,6 +2,10 @@ title: "About This Project" sidebarTitle: "What is This Project?" description: "Discover the story behind 33 JavaScript Concepts. Learn what topics are covered, who this guide is for, and how it helps you become a better developer." +"og:type": "website" +"article:author": "Leonardo Maldonado" +"article:section": "Getting Started" +"article:tag": "33 javascript concepts, javascript learning guide, open source javascript, github javascript project" --- ## The Origin Story diff --git a/docs/getting-started/how-to-learn.mdx b/docs/getting-started/how-to-learn.mdx index e7f2b569..884db41b 100644 --- a/docs/getting-started/how-to-learn.mdx +++ b/docs/getting-started/how-to-learn.mdx @@ -2,6 +2,10 @@ title: "How to Use This Guide" sidebarTitle: "How to Learn" description: "Learn how to study JavaScript effectively. Tips for practicing code, understanding concepts, and getting the most from each lesson in this guide." +"og:type": "website" +"article:author": "Leonardo Maldonado" +"article:section": "Getting Started" +"article:tag": "learn javascript effectively, javascript study tips, coding practice, javascript exercises" --- ## How Each Concept Page Works diff --git a/docs/getting-started/learning-paths.mdx b/docs/getting-started/learning-paths.mdx index 2ef0e285..2b229b11 100644 --- a/docs/getting-started/learning-paths.mdx +++ b/docs/getting-started/learning-paths.mdx @@ -2,6 +2,10 @@ title: "Learning Paths" sidebarTitle: "Learning Paths" description: "Find the right JavaScript learning path for your level. Structured guides for beginners, intermediate developers, and technical interview preparation." +"og:type": "website" +"article:author": "Leonardo Maldonado" +"article:section": "Getting Started" +"article:tag": "javascript learning path, javascript roadmap, beginner javascript, interview prep javascript" --- ## Choose Your Path diff --git a/docs/getting-started/prerequisites.mdx b/docs/getting-started/prerequisites.mdx index 2b76775d..160a76b4 100644 --- a/docs/getting-started/prerequisites.mdx +++ b/docs/getting-started/prerequisites.mdx @@ -2,6 +2,10 @@ title: "Prerequisites & Setup" sidebarTitle: "Prerequisites" description: "Set up your JavaScript learning environment in minutes. All you need is a browser and optionally a code editor. Perfect for complete beginners." +"og:type": "website" +"article:author": "Leonardo Maldonado" +"article:section": "Getting Started" +"article:tag": "javascript setup, javascript environment, beginner javascript, code editor, browser console" --- ## What Do You Need to Learn JavaScript? diff --git a/docs/index.mdx b/docs/index.mdx index bb2512ac..e5bbe191 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -2,6 +2,7 @@ title: "Learn JavaScript" sidebarTitle: "Welcome" description: "Master JavaScript with 33 core concepts. Clear explanations, practical examples, and curated resources for developers at any level." +"article:tag": "javascript concepts, learn javascript, javascript tutorial, javascript fundamentals, web development guide, 33 js concepts" --- Want to truly understand how JavaScript works? Not just copy-paste code, but actually know what's happening under the hood? diff --git a/docs/translations.mdx b/docs/translations.mdx index 9390a4ef..0190aefa 100644 --- a/docs/translations.mdx +++ b/docs/translations.mdx @@ -1,6 +1,10 @@ --- title: "Translations" description: "33 JavaScript Concepts is available in 40+ languages. Find translations in Chinese, Spanish, Portuguese, Korean, and more." +"og:type": "website" +"article:author": "Leonardo Maldonado" +"article:section": "Community" +"article:tag": "javascript translations, multilingual programming, learn javascript languages, 33 concepts translations" --- ## Community Translations From 0106d121ac60de85e213fc453d8def341bedbe4d Mon Sep 17 00:00:00 2001 From: Leonardo Maldonado Date: Tue, 17 Feb 2026 11:17:09 +0100 Subject: [PATCH 4/5] feat(geo): add FAQ sections and citations to all 62 concept pages Wave 4 GEO content enhancements: - FAQ sections with AccordionGroup/Accordion format added to all 62 concept pages - Citations from MDN, ECMAScript specs, State of JS, and Stack Overflow woven into content - Enhanced GEO optimization for AI search visibility (ChatGPT, Perplexity, Gemini, Copilot, Claude) - scope-and-closures.mdx updated with additional citations to existing FAQ section These enhancements improve content depth, credibility, and discoverability across AI search engines. --- docs/beyond/concepts/blob-file-api.mdx | 30 ++++++++++++++-- .../concepts/computed-property-names.mdx | 32 +++++++++++++++-- docs/beyond/concepts/cookies.mdx | 32 +++++++++++++++-- docs/beyond/concepts/custom-events.mdx | 32 +++++++++++++++-- .../beyond/concepts/debouncing-throttling.mdx | 32 +++++++++++++++-- .../concepts/event-bubbling-capturing.mdx | 32 +++++++++++++++-- docs/beyond/concepts/event-delegation.mdx | 32 +++++++++++++++-- docs/beyond/concepts/garbage-collection.mdx | 32 +++++++++++++++-- docs/beyond/concepts/getters-setters.mdx | 32 +++++++++++++++-- docs/beyond/concepts/hoisting.mdx | 32 +++++++++++++++-- docs/beyond/concepts/indexeddb.mdx | 32 +++++++++++++++-- .../beyond/concepts/intersection-observer.mdx | 30 ++++++++++++++-- .../concepts/javascript-type-nuances.mdx | 36 +++++++++++++++++-- docs/beyond/concepts/json-deep-dive.mdx | 30 ++++++++++++++-- .../concepts/localstorage-sessionstorage.mdx | 32 +++++++++++++++-- docs/beyond/concepts/memoization.mdx | 32 +++++++++++++++-- docs/beyond/concepts/memory-management.mdx | 32 +++++++++++++++-- docs/beyond/concepts/mutation-observer.mdx | 30 ++++++++++++++-- docs/beyond/concepts/object-methods.mdx | 32 +++++++++++++++-- docs/beyond/concepts/performance-observer.mdx | 30 ++++++++++++++-- docs/beyond/concepts/property-descriptors.mdx | 32 +++++++++++++++-- docs/beyond/concepts/proxy-reflect.mdx | 32 +++++++++++++++-- .../beyond/concepts/requestanimationframe.mdx | 30 ++++++++++++++-- docs/beyond/concepts/resize-observer.mdx | 30 ++++++++++++++-- docs/beyond/concepts/strict-mode.mdx | 32 +++++++++++++++-- .../concepts/tagged-template-literals.mdx | 32 +++++++++++++++-- docs/beyond/concepts/temporal-dead-zone.mdx | 32 +++++++++++++++-- .../concepts/typed-arrays-arraybuffers.mdx | 30 ++++++++++++++-- docs/beyond/concepts/weakmap-weakset.mdx | 32 +++++++++++++++-- docs/concepts/algorithms-big-o.mdx | 32 +++++++++++++++-- docs/concepts/async-await.mdx | 30 ++++++++++++++-- docs/concepts/call-stack.mdx | 32 +++++++++++++++-- docs/concepts/callbacks.mdx | 30 ++++++++++++++-- docs/concepts/clean-code.mdx | 32 +++++++++++++++-- docs/concepts/currying-composition.mdx | 32 +++++++++++++++-- docs/concepts/data-structures.mdx | 32 +++++++++++++++-- docs/concepts/design-patterns.mdx | 32 +++++++++++++++-- docs/concepts/dom.mdx | 30 ++++++++++++++-- docs/concepts/equality-operators.mdx | 32 +++++++++++++++-- docs/concepts/error-handling.mdx | 32 +++++++++++++++-- docs/concepts/es-modules.mdx | 36 +++++++++++++++++-- docs/concepts/event-loop.mdx | 30 ++++++++++++++-- docs/concepts/factories-classes.mdx | 30 ++++++++++++++-- docs/concepts/generators-iterators.mdx | 30 ++++++++++++++-- docs/concepts/higher-order-functions.mdx | 30 ++++++++++++++-- docs/concepts/http-fetch.mdx | 30 ++++++++++++++-- docs/concepts/iife-modules.mdx | 30 ++++++++++++++-- docs/concepts/inheritance-polymorphism.mdx | 30 ++++++++++++++-- docs/concepts/javascript-engines.mdx | 32 +++++++++++++++-- docs/concepts/map-reduce-filter.mdx | 32 +++++++++++++++-- docs/concepts/modern-js-syntax.mdx | 32 +++++++++++++++-- docs/concepts/object-creation-prototypes.mdx | 30 ++++++++++++++-- docs/concepts/primitive-types.mdx | 32 +++++++++++++++-- docs/concepts/primitives-objects.mdx | 32 +++++++++++++++-- docs/concepts/promises.mdx | 30 ++++++++++++++-- docs/concepts/pure-functions.mdx | 32 +++++++++++++++-- docs/concepts/recursion.mdx | 32 +++++++++++++++-- docs/concepts/regular-expressions.mdx | 32 +++++++++++++++-- docs/concepts/scope-and-closures.mdx | 4 +-- docs/concepts/this-call-apply-bind.mdx | 30 ++++++++++++++-- docs/concepts/type-coercion.mdx | 32 +++++++++++++++-- docs/concepts/web-workers.mdx | 30 ++++++++++++++-- 62 files changed, 1757 insertions(+), 163 deletions(-) diff --git a/docs/beyond/concepts/blob-file-api.mdx b/docs/beyond/concepts/blob-file-api.mdx index e29d845a..f904efc5 100644 --- a/docs/beyond/concepts/blob-file-api.mdx +++ b/docs/beyond/concepts/blob-file-api.mdx @@ -47,9 +47,9 @@ Understanding these APIs unlocks powerful client-side file handling without need ## What is a Blob in JavaScript? -A **[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)** (Binary Large Object) is an immutable, file-like object that represents raw binary data. Think of it as a container that can hold any kind of data: text, images, audio, video, or arbitrary bytes. Blobs are the foundation for file handling in JavaScript, as the File interface is built on top of Blob. +A **[Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob)** (Binary Large Object) is an immutable, file-like object that represents raw binary data. According to the [W3C File API specification](https://www.w3.org/TR/FileAPI/#blob-section), a Blob is a container that can hold any kind of data: text, images, audio, video, or arbitrary bytes. Blobs are the foundation for file handling in JavaScript, as the File interface is built on top of Blob. -Unlike regular JavaScript strings or arrays, Blobs are designed to efficiently handle large amounts of binary data. They're immutable, meaning once created, you can't change their contents. Instead, you create new Blobs from existing ones. +Unlike regular JavaScript strings or arrays, Blobs are designed to efficiently handle large amounts of binary data. As [MDN documents](https://developer.mozilla.org/en-US/docs/Web/API/Blob), they're immutable — once created, you can't change their contents. Instead, you create new Blobs from existing ones. ```javascript // Creating Blobs from different data types @@ -1066,6 +1066,32 @@ document.addEventListener('paste', async (e) => { --- +## Frequently Asked Questions + + + + `File` extends `Blob` with metadata properties: `name`, `lastModified`, and `webkitRelativePath`. A File is always a Blob, but a Blob is not a File. File objects come from user input (``) or drag-and-drop, while Blobs are created programmatically. The W3C File API specification defines this inheritance. + + + + Create a Blob with your content, generate an Object URL with `URL.createObjectURL(blob)`, assign it to an anchor element's `href`, set the `download` attribute to a filename, and trigger a click. Always call `URL.revokeObjectURL()` afterward to free memory. + + + + Object URLs (`blob:...`) are references to in-memory Blob data — they're fast to create but must be manually revoked. Data URLs (`data:...`) encode the full content as a Base64 string — they're larger (about 33% overhead) but self-contained and can be saved or embedded. MDN recommends Object URLs for large files and temporary previews. + + + + Use the `FileReader` API or the modern `file.text()`, `file.arrayBuffer()`, and `file.stream()` methods. `FileReader` uses callbacks while the modern methods return Promises. For text files, `await file.text()` is the simplest approach. For binary data, use `await file.arrayBuffer()`. + + + + Use `blob.slice(start, end)` to split a file into chunks, then upload each chunk separately with `fetch()` and `FormData`. This enables progress tracking, resumable uploads, and avoids server timeout limits. The W3C File API defines `slice()` as a method for creating sub-Blobs from ranges of the original data. + + + +--- + ## Related Concepts diff --git a/docs/beyond/concepts/computed-property-names.mdx b/docs/beyond/concepts/computed-property-names.mdx index 332e2435..4965a9f8 100644 --- a/docs/beyond/concepts/computed-property-names.mdx +++ b/docs/beyond/concepts/computed-property-names.mdx @@ -23,7 +23,7 @@ const obj2 = { [key2]: 'active' }; console.log(obj2); // { status: 'active' } ``` -With **computed property names**, you can use any expression inside square brackets `[]` within an object literal, and JavaScript evaluates that expression to determine the property name. This seemingly small syntax addition enables powerful patterns for dynamic object creation. +With **computed property names**, introduced in the ECMAScript 2015 specification, you can use any expression inside square brackets `[]` within an object literal, and JavaScript evaluates that expression to determine the property name. This seemingly small syntax addition enables powerful patterns for dynamic object creation. **What you'll learn in this guide:** @@ -283,7 +283,7 @@ console.log(defaults); ## Symbol Keys: The Primary Use Case -Symbols are unique, immutable identifiers that can **only** be used as object keys via computed property syntax. This is one of the most important use cases for computed properties. +Symbols are unique, immutable identifiers that can **only** be used as object keys via computed property syntax. According to MDN, this is one of the most important use cases for computed properties and the reason Symbols were designed alongside this syntax in ES2015. ### Why Symbols Need Computed Syntax @@ -549,7 +549,7 @@ console.log(validated[Symbol.for('value')]); // 42 ### Form Field Handling -React and Vue state updates commonly use computed properties: +React and Vue state updates commonly use computed properties. According to Stack Overflow's 2023 Developer Survey, React remains the most popular front-end framework, making this pattern one of the most widely used applications of computed property names: ```javascript // React-style form handler @@ -875,6 +875,32 @@ console.log(obj3.__proto__); // 'just a string' (own property) --- +## Frequently Asked Questions + + + + Computed property names are an ES2015 feature that lets you use any expression inside square brackets `[]` in an object literal to dynamically determine a property's name at runtime. The expression is evaluated, converted to a string (or kept as a Symbol), and used as the key — all in a single expression. + + + + Wrap the variable in square brackets inside the object literal: `{ [myVariable]: value }`. Without brackets, `{ myVariable: value }` creates a property literally named `"myVariable"`. The brackets tell JavaScript to evaluate the expression and use the result as the key name. + + + + Symbol values cannot be expressed as identifiers or string literals in object shorthand. Writing `{ mySymbol: value }` creates a string key `"mySymbol"`, not a Symbol key. Only the computed syntax `{ [mySymbol]: value }` evaluates the variable and uses the actual Symbol as the key, as specified in the ECMAScript standard. + + + + The last one wins — JavaScript silently overwrites previous values with no error. This applies whether the duplicates come from computed properties, static properties, or a mix. MDN documents that this behavior is consistent with how all property assignments work in JavaScript. + + + + Yes. Computed syntax works with method shorthand (`{ [name]() {} }`), generator methods (`{ *[name]() {} }`), async methods (`{ async [name]() {} }`), and accessor properties (`{ get [name]() {}, set [name](v) {} }`). This enables powerful patterns for dynamically-named APIs. + + + +--- + ## Related Concepts diff --git a/docs/beyond/concepts/cookies.mdx b/docs/beyond/concepts/cookies.mdx index 605227c4..480402f9 100644 --- a/docs/beyond/concepts/cookies.mdx +++ b/docs/beyond/concepts/cookies.mdx @@ -21,7 +21,7 @@ console.log(document.cookie) // "username=Alice; theme=dark; lang=en" // Cookie: username=Alice; theme=dark; lang=en ``` -The answer is **cookies**. They're the original browser storage mechanism, and unlike localStorage, cookies are automatically sent to the server with every HTTP request. This makes them essential for authentication, sessions, and any data the server needs to know about. +The answer is **cookies**. Invented by Lou Montulli at Netscape in 1994, they're the original browser storage mechanism, and unlike localStorage, cookies are automatically sent to the server with every HTTP request. This makes them essential for authentication, sessions, and any data the server needs to know about. **What you'll learn in this guide:** @@ -505,7 +505,7 @@ console.log(document.cookie) // sessionId won't appear ### SameSite: CSRF Protection -The [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#samesitesamesite-value) attribute controls when cookies are sent with cross-site requests: +The [`SameSite`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Set-Cookie#samesitesamesite-value) attribute controls when cookies are sent with cross-site requests. According to web.dev's SameSite cookies guide, Chrome changed the default from `None` to `Lax` in 2020, significantly improving CSRF protection across the web: @@ -631,7 +631,7 @@ Cookies set by a different domain than the one you're visiting: ## Third-Party Cookie Deprecation -Major browsers are phasing out third-party cookies for privacy: +Major browsers are phasing out third-party cookies for privacy. According to MDN's third-party cookies documentation, this represents one of the most significant changes to web tracking since cookies were invented: | Browser | Status | |---------|--------| @@ -965,6 +965,32 @@ With `Partitioned`, the cookie is isolated per top-level site: --- +## Frequently Asked Questions + + + + Cookies are automatically sent to the server with every HTTP request and have a ~4KB size limit, while localStorage stays in the browser and offers ~5–10MB. Use cookies when the server needs the data (authentication, sessions). Use localStorage for client-only data like UI preferences that doesn't need to travel with requests. + + + + `HttpOnly` prevents JavaScript from accessing the cookie via `document.cookie`. This protects against XSS attacks — even if an attacker injects malicious JavaScript, they cannot steal HttpOnly cookies. According to MDN, HttpOnly can only be set by the server via the `Set-Cookie` header, not by client-side JavaScript. + + + + `SameSite` controls whether cookies are sent with cross-site requests. `Strict` blocks all cross-site sending, `Lax` (the default since Chrome 80) allows cookies on top-level navigation but blocks them on cross-site POST requests, and `None` sends cookies on all requests but requires the `Secure` attribute. + + + + Set the cookie with `max-age=0` or an `expires` date in the past using the same `path` and `domain` attributes as when it was originally set. There is no direct delete method — this is a common source of bugs when the path or domain doesn't match the original cookie. + + + + Yes. Safari has blocked third-party cookies by default since 2020, Firefox blocks them in Enhanced Tracking Protection, and Chrome is rolling out restrictions through 2024–2025. According to MDN, partitioned cookies (CHIPS) provide an alternative for legitimate cross-site use cases like embedded widgets. + + + +--- + ## Related Concepts diff --git a/docs/beyond/concepts/custom-events.mdx b/docs/beyond/concepts/custom-events.mdx index 052186cc..7599801d 100644 --- a/docs/beyond/concepts/custom-events.mdx +++ b/docs/beyond/concepts/custom-events.mdx @@ -45,7 +45,7 @@ The answer is **custom events**. They let you create your own event types, attac ## What is a Custom Event? -A **[custom event](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)** is a developer-defined event that you create, dispatch, and listen for in JavaScript. Unlike built-in events like `click` or `keydown` triggered by user actions, custom events are triggered programmatically using `dispatchEvent()`. The `CustomEvent` constructor extends the base `Event` interface, adding a `detail` property for passing data to listeners. +A **[custom event](https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent)** is a developer-defined event that you create, dispatch, and listen for in JavaScript. Unlike built-in events like `click` or `keydown` triggered by user actions, custom events are triggered programmatically using `dispatchEvent()`. The `CustomEvent` constructor extends the base `Event` interface, adding a `detail` property for passing data to listeners. [Can I Use data](https://caniuse.com/customevent) shows the `CustomEvent` constructor is supported in over 98% of browsers globally. Custom events work with any [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget), including DOM elements, the `document`, `window`, and even custom objects that extend `EventTarget`. @@ -93,7 +93,7 @@ Think of custom events like a radio broadcast: └─────────────────────────────────────────────────────────────────────────────┘ ``` -This decoupling is the superpower of custom events. Components can communicate without importing each other or knowing each other exists. +This decoupling is the superpower of custom events. As MDN's guide on [creating and triggering events](https://developer.mozilla.org/en-US/docs/Web/Events/Creating_and_triggering_events) explains, this pub/sub pattern lets components communicate without importing each other or knowing each other exists. --- @@ -265,7 +265,7 @@ someElement.dispatchEvent(event) ### Important: dispatchEvent is Synchronous -Unlike native browser events (which are processed asynchronously through the event loop), `dispatchEvent()` is **synchronous**. All listeners execute immediately before `dispatchEvent()` returns: +Unlike native browser events (which are processed asynchronously through the event loop), `dispatchEvent()` is **synchronous**. As the [W3C DOM specification](https://dom.spec.whatwg.org/#dom-eventtarget-dispatchevent) states, dispatching is a synchronous operation — all listeners execute immediately before `dispatchEvent()` returns: ```javascript console.log('1: Before dispatch') @@ -841,6 +841,32 @@ button.dispatchEvent(new CustomEvent('customClick')) --- +## Frequently Asked Questions + + + + Use the `CustomEvent` constructor: `new CustomEvent('eventName', { detail: data })`. The `detail` property can hold any JavaScript value — objects, arrays, or primitives. Then dispatch it on any element with `element.dispatchEvent(event)`. + + + + No — custom events do not bubble by default. You must explicitly set `bubbles: true` in the options object to enable bubbling. Without it, only listeners directly on the dispatching element will receive the event, as documented in the W3C DOM specification. + + + + `CustomEvent` extends `Event` with one key addition: the `detail` property for passing arbitrary data. If you don't need to send data to listeners, `new Event('name')` works fine. MDN recommends `CustomEvent` when you need to communicate data alongside the event. + + + + `dispatchEvent()` is synchronous — all listeners execute immediately before the method returns. This differs from native browser events, which are processed asynchronously through the event loop. You can use the return value of `dispatchEvent()` to check if any listener called `preventDefault()`. + + + + No. Custom events do not have corresponding `on*` properties like native events. `element.onmyEvent = handler` does nothing — you must use `addEventListener()` to listen for custom events. This is a common mistake MDN specifically warns about. + + + +--- + ## Related Concepts diff --git a/docs/beyond/concepts/debouncing-throttling.mdx b/docs/beyond/concepts/debouncing-throttling.mdx index 695f2c71..ab5f98f9 100644 --- a/docs/beyond/concepts/debouncing-throttling.mdx +++ b/docs/beyond/concepts/debouncing-throttling.mdx @@ -22,7 +22,7 @@ searchInput.addEventListener('input', debounce((e) => { }, 300)) ``` -**[Debouncing](https://developer.mozilla.org/en-US/docs/Glossary/Debounce)** and **[throttling](https://developer.mozilla.org/en-US/docs/Glossary/Throttle)** are two techniques that control how often a function can execute. They're essential for handling high-frequency events like scrolling, resizing, typing, and mouse movement without destroying your app's performance. +**[Debouncing](https://developer.mozilla.org/en-US/docs/Glossary/Debounce)** and **[throttling](https://developer.mozilla.org/en-US/docs/Glossary/Throttle)** are two techniques that control how often a function can execute. According to MDN, both patterns are essential for handling high-frequency events like scrolling, resizing, typing, and mouse movement without destroying your app's performance. The scroll event alone can fire hundreds of times per second on modern browsers. **What you'll learn in this guide:** @@ -497,7 +497,7 @@ function throttle(fn, interval, options = {}) { ## Using Lodash in Production -For production applications, use battle-tested libraries like [Lodash](https://lodash.com/). They handle edge cases, provide TypeScript types, and are thoroughly tested. +For production applications, use battle-tested libraries like [Lodash](https://lodash.com/). With over 30 million weekly npm downloads, Lodash's debounce and throttle implementations handle edge cases, provide TypeScript types, and are thoroughly tested across thousands of production applications. ### Installation @@ -691,7 +691,7 @@ document.addEventListener('mousemove', (e) => { ## requestAnimationFrame Alternative -For visual updates tied to rendering (animations, scroll effects), [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) is often better than throttle. It syncs with the browser's repaint cycle (typically 60fps ≈ 16ms) and is scheduled by the [event loop](/concepts/event-loop) as a special render-related callback. +For visual updates tied to rendering (animations, scroll effects), [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) is often better than throttle. As web.dev's rendering performance guide explains, rAF syncs with the browser's repaint cycle (typically 60fps ≈ 16ms) and is scheduled by the [event loop](/concepts/event-loop) as a special render-related callback. ```javascript function throttleWithRAF(fn) { @@ -987,6 +987,32 @@ throttle(scroll, 100) // 100-150ms for scroll (smooth but efficient) --- +## Frequently Asked Questions + + + + Debounce delays execution until events stop coming for a specified duration — it fires once after a burst. Throttle limits execution to at most once per interval during continuous events — it fires at regular intervals. Use debounce when you care about the final value (search), and throttle when you need periodic updates (scroll tracking). + + + + A delay of 250–400 milliseconds is standard for search autocomplete. This gives users enough time to finish typing a word without feeling unresponsive. Lodash's `maxWait` option can force execution after a maximum delay (e.g., 2 seconds) during long typing sessions, combining debounce and throttle behavior. + + + + Always cancel pending executions in a cleanup function. Return a cleanup from `useEffect` that calls `handler.cancel()` and removes event listeners. According to the React documentation, forgetting cleanup is one of the most common sources of memory leaks in React applications using debounce or throttle. + + + + Yes, for visual updates like animations and scroll-linked effects. `requestAnimationFrame` syncs with the browser's 60fps repaint cycle (~16ms intervals), producing smoother results than a fixed throttle interval. Use throttle for non-visual tasks like API calls, analytics tracking, and infinite scroll loading. + + + + Creating a debounced function inside an event handler creates a new function (with its own timer) on every event. Each instance has a separate timer, so debouncing never kicks in. Always create the debounced function once outside the handler and reuse it — the closure maintains state between calls. + + + +--- + ## Related Concepts diff --git a/docs/beyond/concepts/event-bubbling-capturing.mdx b/docs/beyond/concepts/event-bubbling-capturing.mdx index 0b2ff142..e87efc33 100644 --- a/docs/beyond/concepts/event-bubbling-capturing.mdx +++ b/docs/beyond/concepts/event-bubbling-capturing.mdx @@ -50,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 @@ -82,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`. @@ -414,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 | |-------|----------|---------------------| @@ -679,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 175620f7..fb1daeff 100644 --- a/docs/beyond/concepts/event-delegation.mdx +++ b/docs/beyond/concepts/event-delegation.mdx @@ -48,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. @@ -152,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 @@ -475,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 @@ -824,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 56aacf45..4bd01701 100644 --- a/docs/beyond/concepts/garbage-collection.mdx +++ b/docs/beyond/concepts/garbage-collection.mdx @@ -15,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:** @@ -232,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. @@ -759,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 875571a1..eed81ac3 100644 --- a/docs/beyond/concepts/getters-setters.mdx +++ b/docs/beyond/concepts/getters-setters.mdx @@ -51,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 = { @@ -866,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 @@ -973,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 = { @@ -1146,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 cce9973a..b2958f1f 100644 --- a/docs/beyond/concepts/hoisting.mdx +++ b/docs/beyond/concepts/hoisting.mdx @@ -48,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. @@ -125,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!) @@ -571,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`. @@ -762,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 6cdc6c56..3a043798 100644 --- a/docs/beyond/concepts/indexeddb.mdx +++ b/docs/beyond/concepts/indexeddb.mdx @@ -29,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:** @@ -50,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. @@ -518,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) @@ -960,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 55e9fd43..fefe518a 100644 --- a/docs/beyond/concepts/intersection-observer.mdx +++ b/docs/beyond/concepts/intersection-observer.mdx @@ -42,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.** --- @@ -102,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. --- @@ -978,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 00666683..9a4f2074 100644 --- a/docs/beyond/concepts/javascript-type-nuances.mdx +++ b/docs/beyond/concepts/javascript-type-nuances.mdx @@ -309,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 @@ -454,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`: @@ -651,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 @@ -1141,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 92533292..08f51313 100644 --- a/docs/beyond/concepts/json-deep-dive.mdx +++ b/docs/beyond/concepts/json-deep-dive.mdx @@ -43,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 @@ -59,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. --- @@ -969,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 f1e26eb2..eed2cec4 100644 --- a/docs/beyond/concepts/localstorage-sessionstorage.mdx +++ b/docs/beyond/concepts/localstorage-sessionstorage.mdx @@ -25,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:** @@ -48,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. @@ -600,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). --- @@ -912,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 a26c7e9e..b9a8893e 100644 --- a/docs/beyond/concepts/memoization.mdx +++ b/docs/beyond/concepts/memoization.mdx @@ -52,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. @@ -262,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 @@ -630,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) { @@ -803,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 5008b919..a7ccec21 100644 --- a/docs/beyond/concepts/memory-management.mdx +++ b/docs/beyond/concepts/memory-management.mdx @@ -20,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:** @@ -292,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: ``` ┌─────────────────────────────────────────────────────────────────────────┐ @@ -578,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 @@ -954,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 f69c4145..86274edf 100644 --- a/docs/beyond/concepts/mutation-observer.mdx +++ b/docs/beyond/concepts/mutation-observer.mdx @@ -72,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. --- @@ -441,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') @@ -856,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 8535ce69..e4c97220 100644 --- a/docs/beyond/concepts/object-methods.mdx +++ b/docs/beyond/concepts/object-methods.mdx @@ -42,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 } @@ -262,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 = { @@ -319,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 } @@ -717,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 f6691538..fb548fde 100644 --- a/docs/beyond/concepts/performance-observer.mdx +++ b/docs/beyond/concepts/performance-observer.mdx @@ -26,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:** @@ -220,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) @@ -964,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 96cac599..feef678e 100644 --- a/docs/beyond/concepts/property-descriptors.mdx +++ b/docs/beyond/concepts/property-descriptors.mdx @@ -53,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" } @@ -348,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 = {} @@ -483,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 } @@ -838,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 05e06c4f..324fe33a 100644 --- a/docs/beyond/concepts/proxy-reflect.mdx +++ b/docs/beyond/concepts/proxy-reflect.mdx @@ -31,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:** @@ -351,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 | |-----------|-----------------|--------------| @@ -408,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) { @@ -718,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 ea37eb25..ae0d1874 100644 --- a/docs/beyond/concepts/requestanimationframe.mdx +++ b/docs/beyond/concepts/requestanimationframe.mdx @@ -28,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:** @@ -49,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. @@ -971,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 0f8f7ff8..4befa4d5 100644 --- a/docs/beyond/concepts/resize-observer.mdx +++ b/docs/beyond/concepts/resize-observer.mdx @@ -44,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: @@ -592,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 | |---------|---------------| @@ -842,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 b2e5d4fe..83c4f426 100644 --- a/docs/beyond/concepts/strict-mode.mdx +++ b/docs/beyond/concepts/strict-mode.mdx @@ -48,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. --- @@ -135,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: @@ -196,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 @@ -627,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 `