more content, but broken js
· 1 year ago
2fbebd27ae03923ff7bd8cd33b4bb13ab30832fe
Parent:
cf33d3f6a
1 file changed +1971 −828
- javascript-for-architects.html +1971 −828
Diff
--- a/javascript-for-architects.html +++ b/javascript-for-architects.html @@ -10,7 +10,7 @@ <!-- SEO Meta Description --> <meta name="description" content="Comprehensive interactive cheatsheet for modern JavaScript (ES6+), frontend frameworks (React, Vue, Angular, Svelte), Web APIs, tooling (Vite, Webpack), and architectural patterns for developers and architects."> <!-- Keywords --> - <meta name="keywords" content="JavaScript, ES6, React, Vue, Angular, Svelte, Frontend, Cheatsheet, Web APIs, DOM, Fetch, Promises, Async/Await, Hooks, Context API, Redux, Vite, Webpack, Node.js, TypeScript, HTML, CSS, Developer Guide, Programming, Architecture"> + <meta name="keywords" content="JavaScript, ES6, React, Vue, Angular, Svelte, Frontend, Cheatsheet, Web APIs, DOM, Fetch, Promises, Async/Await, Hooks, Context API, Redux, Vite, Webpack, Node.js, TypeScript, HTML, CSS, Developer Guide, Programming, Architecture, State Management, Testing, Tooling, Performance, Security, Accessibility, SSR, SSG, CSR"> <!-- Canonical URL --> <link rel="canonical" href="https://cheatsheets.davidveksler.com/javascript-for-architects.html"> @@ -24,7 +24,7 @@ <meta property="og:image:alt" content="Visual diagram connecting JavaScript core features, React concepts, Vue, Angular, Svelte, Web APIs, and frontend tooling for architects."> <meta property="og:site_name" content="David Veksler Cheatsheets"> <meta property="article:published_time" content="2024-01-20T09:00:00Z"> - <meta property="article:modified_time" content="2025-05-12T10:00:00Z"> <!-- Update Last Modified --> + <meta property="article:modified_time" content="2025-05-12T11:00:00Z"> <!-- Updated Last Modified --> <meta property="article:author" content="https://www.linkedin.com/in/davidveksler/"> @@ -59,22 +59,22 @@ } }, "datePublished": "2024-01-20T09:00:00Z", - "dateModified": "2025-05-12T10:00:00Z", // Update Last Modified + "dateModified": "2025-05-12T11:00:00Z", // Updated Last Modified "mainEntityOfPage": { "@type": "WebPage", "@id": "https://cheatsheets.davidveksler.com/javascript-for-architects.html" }, - "keywords": "JavaScript, ES6, React, Vue, Angular, Svelte, Frontend, Cheatsheet, Web APIs, DOM, Fetch, Promises, Async/Await, Hooks, Context API, Redux, Vite, Webpack, Node.js, TypeScript, HTML, CSS, Developer Guide, Programming, Architecture, State Management, Testing, Tooling" + "keywords": "JavaScript, ES6, React, Vue, Angular, Svelte, Frontend, Cheatsheet, Web APIs, DOM, Fetch, Promises, Async/Await, Hooks, Context API, Redux, Vite, Webpack, Node.js, TypeScript, HTML, CSS, Developer Guide, Programming, Architecture, State Management, Testing, Tooling, Performance, Security, Accessibility, SSR, SSG, CSR" } </script> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css"> <script src="https://cdn.jsdelivr.net/npm/[email protected]/leader-line.min.js"></script> - <!-- Optional: Add Prism.js for code highlighting --> - <!-- <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css" rel="stylesheet" /> --> - <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script> --> - <!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script> --> + <!-- Prism.js for code highlighting --> + <link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-okaidia.min.css" rel="stylesheet" /> + <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script> + <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script> <style> @@ -290,9 +290,10 @@ } .collapse-content li strong { color: var(--text-color-highlight); display: block; margin-bottom: 0.2rem; font-weight: 600; } .collapse-content p { font-size: 0.9rem; margin-bottom: 0.6rem; line-height: 1.55; } - .collapse-content code { font-size: 0.85rem; color: #c2185b; background-color: #f8f9fa; padding: 0.2em 0.4em; border-radius: 3px; font-family: Consolas, Menlo, Monaco, 'Courier New', monospace; border: 1px solid #eee;} - .collapse-content pre { background-color: #f8f9fa; border: 1px solid #eee; padding: 0.8rem; border-radius: 4px; font-size: 0.85rem; overflow-x: auto;} - .collapse-content pre code { background-color: transparent; border: none; padding: 0; } + /* Updated code styling for Prism integration */ + .collapse-content code:not(pre > code) { font-size: 0.85em; color: #c2185b; background-color: #f8f9fa; padding: 0.2em 0.4em; border-radius: 3px; font-family: Consolas, Menlo, Monaco, 'Courier New', monospace; border: 1px solid #eee;} + .collapse-content pre { background-color: #282c34 !important; /* Okaidia theme background */ color: #abb2bf; /* Okaidia text color */ border: 1px solid #3a404c; padding: 1rem; border-radius: 4px; font-size: 0.85rem; overflow-x: auto; margin-top: 0.5rem; margin-bottom: 1rem; } + .collapse-content pre code { background-color: transparent !important; border: none; padding: 0; color: inherit; font-size: inherit; } .row > * { margin-bottom: 2rem; } @@ -367,69 +368,66 @@ <div class="col-lg-4 col-md-6"> <div class="info-card card-core" id="card-js-overview"> <div class="card-body"> - <h5><i class="bi bi-code-slash" aria-hidden="true" data-bs-toggle="tooltip" data-bs-placement="top" title="Code Icon"></i> JS Overview</h5> + <h5><i class="bi bi-code-slash" aria-hidden="true"></i> JS Overview</h5> <div class="card-content-wrapper"> - <p class="summary">A high-level, <span class="term" data-bs-toggle="tooltip" title="Types are checked during runtime, not compile time.">dynamically typed</span>, <span class="term" data-bs-toggle="tooltip" title="Code is executed line by line on a single main thread.">single-threaded</span> language primarily used for web development (browsers, Node.js). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/About" target="_blank" rel="noopener noreferrer" data-bs-toggle="tooltip" title="External link: MDN About JavaScript">MDN Intro</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsOverview" aria-expanded="false" aria-controls="collapseJsOverview"> - Details <i class="bi bi-chevron-down" aria-hidden="true"></i> - </button> + <p class="summary">High-level, <span class="term">dynamically typed</span>, <span class="term">single-threaded</span> language with an <span class="term">event loop</span> for non-blocking asynchronous operations. Primarily for web browsers & Node.js servers. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/About" target="_blank">MDN Intro</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsOverview" aria-expanded="false" aria-controls="collapseJsOverview"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsOverview"> <h6>Purpose</h6> - <p>Adds interactivity to web pages, builds web/mobile apps, powers servers (Node.js), and more.</p> + <p>Adds interactivity to web pages, builds full-stack web/mobile apps, powers servers (Node.js), automation, and more.</p> <h6>Key Characteristics</h6> <ul> - <li><strong>Dynamic Typing:</strong> Variable types are determined at runtime.</li> - <li><strong>Interpreted:</strong> Typically executed directly by an engine (e.g., V8, SpiderMonkey) without explicit compilation step for distribution.</li> - <li><strong>Event Loop:</strong> Handles asynchronous operations non-blockingly despite being single-threaded. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop" target="_blank" rel="noopener noreferrer">Event Loop</a></li> - <li><strong>Prototype-based Inheritance:</strong> Objects inherit directly from other objects.</li> + <li><strong>Dynamic Typing:</strong> Variable types determined at runtime. Offers flexibility but requires careful handling.</li> + <li><strong>Interpreted/JIT-Compiled:</strong> Modern engines (V8, SpiderMonkey) use Just-In-Time compilation for performance.</li> + <li><strong>Event Loop:</strong> Core mechanism enabling non-blocking I/O by offloading operations and processing results via a callback queue. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop" target="_blank">Event Loop Explained</a></li> + <li><strong>Prototype-based Inheritance:</strong> Objects inherit directly from other objects (prototypes). ES6 Classes provide syntax sugar.</li> + <li><strong>Multi-paradigm:</strong> Supports procedural, object-oriented (via prototypes/classes), and functional programming styles.</li> </ul> - <!-- Detailed content needed --> </div> </div> </div> <div class="col-lg-4 col-md-6"> <div class="info-card card-core" id="card-js-vars"> <div class="card-body"> - <h5><i class="bi bi-bounding-box-circles" aria-hidden="true" data-bs-toggle="tooltip" data-bs-placement="top" title="Scope Icon"></i> Variables & Scope</h5> + <h5><i class="bi bi-bounding-box-circles" aria-hidden="true"></i> Variables & Scope</h5> <div class="card-content-wrapper"> - <p class="summary">Declare variables using <span class="term" data-bs-toggle="tooltip" title="Modern block-scoped variable declaration."><code>let</code></span>, <span class="term" data-bs-toggle="tooltip" title="Modern block-scoped constant declaration (cannot be reassigned)."><code>const</code></span> (preferred), or legacy <span class="term" data-bs-toggle="tooltip" title="Older function-scoped variable declaration (avoid in modern JS)."><code>var</code></span>. Understand block vs. function scope. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Declarations" target="_blank" rel="noopener noreferrer">MDN Declarations</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsVars" aria-expanded="false" aria-controls="collapseJsVars"> - Details <i class="bi bi-chevron-down" aria-hidden="true"></i> - </button> + <p class="summary">Declare using <span class="term"><code>let</code></span> (reassignable, block-scoped), <span class="term"><code>const</code></span> (constant reference, block-scoped), or legacy <span class="term"><code>var</code></span> (function-scoped, hoisted). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Grammar_and_types#Declarations" target="_blank">MDN Declarations</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsVars" aria-expanded="false" aria-controls="collapseJsVars"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsVars"> <h6>Declarations</h6> <ul> - <li><strong><code>const</code>:</strong> Block-scoped. Must be initialized. Cannot be reassigned. (Object/array contents *can* be mutated).</li> - <li><strong><code>let</code>:</strong> Block-scoped. Can be reassigned. Can be declared without initialization.</li> - <li><strong><code>var</code>:</strong> Function-scoped (or global). Subject to hoisting issues. Avoid in modern code.</li> + <li><strong><code>const</code>:</strong> Block-scoped (`{}`). Must be initialized. Cannot be reassigned. Use when the variable reference shouldn't change. (Note: Object/array *contents* can still be mutated).</li> + <li><strong><code>let</code>:</strong> Block-scoped (`{}`). Can be reassigned. Can be declared without initialization (`undefined` by default). Use for variables that need to change value.</li> + <li><strong><code>var</code>:</strong> Function-scoped (or global). Subject to hoisting issues (declaration moved up, initialization stays). Generally avoid in modern ES6+ code.</li> </ul> <h6>Scope</h6> <ul> - <li><strong>Block Scope:</strong> Variables declared with `let` or `const` inside `{...}` blocks (like `if`, `for`) are only accessible within that block.</li> - <li><strong>Function Scope:</strong> Variables declared with `var` are accessible anywhere within the function they are defined in.</li> - <li><strong>Global Scope:</strong> Variables declared outside any function/block.</li> + <li><strong>Block Scope:</strong> Variables (`let`/`const`) only accessible within the `{...}` block (e.g., `if`, `for`, `while`) where defined.</li> + <li><strong>Function Scope:</strong> Variables (`var`) accessible anywhere within the function they are defined in, regardless of blocks.</li> + <li><strong>Global Scope:</strong> Variables declared outside any function/block. Accessible everywhere (avoid polluting global scope).</li> + <li><strong>Lexical Scope:</strong> Inner functions have access to variables of their outer functions (forms closures).</li> </ul> - <h6>Hoisting</h6> - <p><code>var</code> declarations are conceptually "moved" to the top of their scope, but initializations are not. `let` and `const` are hoisted but not initialized (Temporal Dead Zone). Accessing them before declaration throws an error. <a href="https://developer.mozilla.org/en-US/docs/Glossary/Hoisting" target="_blank">Hoisting</a></p> - <pre><code class="language-javascript">// Example -if (true) { - let blockVar = "I'm block scoped"; - const blockConst = "Me too!"; - var funcVar = "I'm function scoped!"; // if this 'if' is in global, funcVar is global -} -console.log(typeof blockVar); // undefined (ReferenceError if accessed directly) -// console.log(blockConst); // ReferenceError -// console.log(funcVar); // "I'm function scoped!" (if 'if' block was global) - -function testScope() { - if (true) { var funcVarInner = "Inner func scope"; } - // console.log(funcVarInner); // "Inner func scope" + <h6>Hoisting & Temporal Dead Zone (TDZ)</h6> + <p>Declarations are conceptually "hoisted" (moved to top of scope) during compilation. `var` declarations are initialized with `undefined`. `let` and `const` declarations are hoisted but *not* initialized, creating a "Temporal Dead Zone" until the declaration line is reached. Accessing them in the TDZ throws a `ReferenceError`. <a href="https://developer.mozilla.org/en-US/docs/Glossary/Hoisting" target="_blank">Hoisting</a> | <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_TDZ" target="_blank">TDZ</a></p> + <pre><code class="language-javascript">function scopeTest() { + // console.log(letVar); // ReferenceError: Cannot access 'letVar' before initialization (TDZ) + console.log(varVar); // undefined (Hoisted, initialized with undefined) + + let letVar = "I am block scoped"; + var varVar = "I am function scoped"; + + if (true) { + let innerLet = "Inner block"; + const innerConst = "Inner constant"; + } + // console.log(innerLet); // ReferenceError: innerLet is not defined } -// console.log(typeof funcVarInner); // undefined (ReferenceError) +scopeTest(); +// console.log(varVar); // ReferenceError: varVar is not defined (outside function scope) </code></pre> </div> </div> @@ -437,124 +435,290 @@ function testScope() { <div class="col-lg-4 col-md-6"> <div class="info-card card-core" id="card-js-types"> <div class="card-body"> - <h5><i class="bi bi-tags" aria-hidden="true" data-bs-toggle="tooltip" data-bs-placement="top" title="Data Types Icon"></i> Data Types</h5> + <h5><i class="bi bi-tags" aria-hidden="true"></i> Data Types</h5> <div class="card-content-wrapper"> - <p class="summary">JS has <span class="term" data-bs-toggle="tooltip" title="string, number, boolean, null, undefined, symbol, bigint">primitive types</span> and the <span class="term" data-bs-toggle="tooltip" title="Collections of key-value pairs, including arrays and functions.">Object</span> type. Beware of <span class="term" data-bs-toggle="tooltip" title="Automatic conversion between types (e.g., '5' + 1 = '51').">type coercion</span>. Use `typeof` operator. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures" target="_blank" rel="noopener noreferrer">MDN Data Structures</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsTypes" aria-expanded="false" aria-controls="collapseJsTypes"> - Details <i class="bi bi-chevron-down" aria-hidden="true"></i> - </button> + <p class="summary">JS has 7 <span class="term">primitive types</span> (immutable) and the <span class="term">Object</span> type (mutable). Use `typeof` for basic checks. Beware <span class="term">type coercion</span>; prefer strict equality (`===`). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures" target="_blank">MDN Data Structures</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsTypes" aria-expanded="false" aria-controls="collapseJsTypes"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsTypes"> <h6>Primitives (Immutable)</h6> <ul> - <li><strong>string:</strong> Textual data (e.g., `"hello"`).</li> - <li><strong>number:</strong> Numeric values (e.g., `42`, `3.14`). Includes `Infinity`, `-Infinity`, `NaN`.</li> + <li><strong>string:</strong> Textual data (e.g., `"hello"`, `'world'`, `` `template` ``).</li> + <li><strong>number:</strong> Numeric values (e.g., `42`, `3.14`, `1e6`). Includes special values `Infinity`, `-Infinity`, `NaN` (Not-a-Number).</li> <li><strong>boolean:</strong> Logical values (`true`, `false`).</li> - <li><strong>null:</strong> Intentional absence of any object value. (`typeof null` is `"object"` - a historical quirk).</li> - <li><strong>undefined:</strong> Variable declared but not yet assigned a value.</li> - <li><strong>symbol (ES6):</strong> Unique and immutable primitive value, often used as object property keys.</li> - <li><strong>bigint (ES2020):</strong> Arbitrary precision integers (e.g., `9007199254740991n`).</li> + <li><strong>null:</strong> Intentional absence of any object value. Represents "no value".</li> + <li><strong>undefined:</strong> Variable declared but not yet assigned a value; also default function return value.</li> + <li><strong>symbol (ES6):</strong> Unique, immutable identifier, often used as non-string object property keys. `Symbol('desc')`.</li> + <li><strong>bigint (ES2020):</strong> Arbitrary precision integers (e.g., `9007199254740991n`). For numbers larger than `Number.MAX_SAFE_INTEGER`.</li> </ul> <h6>Object (Mutable)</h6> <ul> - <li><strong>object:</strong> Collection of properties (key-value pairs). Includes arrays, functions, Date, RegExp, etc.</li> + <li><strong>object:</strong> Collection of properties (key-value pairs). Includes arrays, functions, Date, RegExp, Map, Set, etc. Passed by reference.</li> + </ul> + <h6>Type Checking (`typeof`)</h6> + <pre><code class="language-javascript">typeof "hello" // "string" +typeof 42 // "number" +typeof true // "boolean" +typeof undefined // "undefined" +typeof null // "object" (historical quirk!) +typeof {} // "object" +typeof [] // "object" (arrays are objects) +typeof function(){} // "function" (functions are objects) +typeof Symbol('id') // "symbol" +typeof 123n // "bigint" +typeof NaN // "number" +</code></pre> + <h6>Type Coercion & Equality</h6> + <p>JavaScript automatically converts types in certain operations (coercion). This can lead to unexpected results with loose equality (`==`). Always prefer strict equality (`===`) which checks both value and type without coercion. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness" target="_blank">Equality Comparisons</a></p> + <pre><code class="language-javascript">console.log('5' == 5); // true (String '5' coerced to Number 5) +console.log('5' === 5); // false (Types are different) +console.log(null == undefined); // true (Special rule) +console.log(null === undefined);// false (Types are different) +console.log(0 == false); // true (Boolean false coerced to Number 0) +console.log(0 === false); // false (Types are different) +</code></pre> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-core" id="card-js-operators"> + <div class="card-body"> + <h5><i class="bi bi-calculator" aria-hidden="true"></i> Operators</h5> + <div class="card-content-wrapper"> + <p class="summary">Symbols performing operations on values (operands). Includes arithmetic (`+`, `-`, `*`, `/`, `%`), comparison (`>`, `<`, `===`, `!==`), logical (`&&`, `||`, `!`), assignment (`=`, `+=`), and others. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators" target="_blank">MDN Operators</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsOperators" aria-expanded="false" aria-controls="collapseJsOperators"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseJsOperators"> + <h6>Common Operator Types</h6> + <ul> + <li><strong>Arithmetic:</strong> `+` (addition/concatenation), `-` (subtraction), `*` (multiplication), `/` (division), `%` (remainder/modulo), `**` (exponentiation ES7), `++` (increment), `--` (decrement).</li> + <li><strong>Assignment:</strong> `=` (assign), `+=`, `-=`, `*=`, `/=`, `%=` (compound assignment).</li> + <li><strong>Comparison:</strong> `==` (loose equality), `!=` (loose inequality), `===` (strict equality), `!==` (strict inequality), `>`, `>=`, `<`, `<=`.</li> + <li><strong>Logical:</strong> `&&` (AND), `||` (OR), `!` (NOT). Short-circuiting behavior is important.</li> + <li><strong>Bitwise:</strong> `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>` (Less common in frontend).</li> + <li><strong>String:</strong> `+` (concatenation).</li> + <li><strong>Conditional (Ternary):</strong> `condition ? valueIfTrue : valueIfFalse`.</li> + <li><strong>Type:</strong> `typeof` (returns string indicating type), `instanceof` (checks if object is instance of a class/constructor).</li> + <li><strong>Comma:</strong> `,` (Evaluates multiple expressions, returns the last one).</li> + <li><strong>Spread/Rest (`...`):</strong> Used in arrays, objects, function calls/definitions (See Modern JS).</li> + <li><strong>Optional Chaining (`?.`):</strong> Access nested properties safely (See Modern JS).</li> + <li><strong>Nullish Coalescing (`??`):</strong> Provide default for `null` or `undefined` (See Modern JS).</li> + </ul> + <p>Operator precedence determines the order of evaluation. Use parentheses `()` to enforce specific order. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence" target="_blank">Operator Precedence</a></p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-core" id="card-js-control-flow"> + <div class="card-body"> + <h5><i class="bi bi-alt" aria-hidden="true"></i> Control Flow</h5> + <div class="card-content-wrapper"> + <p class="summary">Directs the order of execution. Conditionals (`if/else`, `switch`) branch execution. Loops (`for`, `while`, `do...while`, `for...of`, `for...in`) repeat execution. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling" target="_blank">MDN Control Flow</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsControlFlow" aria-expanded="false" aria-controls="collapseJsControlFlow"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseJsControlFlow"> + <h6>Conditionals</h6> + <ul> + <li><strong>`if...else if...else`</strong>: Execute blocks based on conditions.</li> + <li><strong>`switch`</strong>: Efficiently compare one value against multiple `case` values. Use `break` to exit.</li> + </ul> + <h6>Loops</h6> + <ul> + <li><strong>`for` loop</strong>: `for (initialization; condition; final-expression) { ... }` - Standard loop for known iteration counts.</li> + <li><strong>`while` loop</strong>: `while (condition) { ... }` - Loop while condition is true. Condition checked *before* execution.</li> + <li><strong>`do...while` loop</strong>: `do { ... } while (condition);` - Loop while condition is true. Condition checked *after* execution (always runs at least once).</li> + <li><strong>`for...in` loop</strong>: `for (const key in object) { ... }` - Iterates over enumerable property *keys* (usually strings) of an object. Avoid for arrays.</li> + <li><strong>`for...of` loop (ES6)</strong>: `for (const value of iterable) { ... }` - Iterates over the *values* of iterable objects (Arrays, Strings, Maps, Sets). Preferred way to loop over array values.</li> </ul> - <h6>Type Coercion</h6> - <p>JavaScript often implicitly converts types during operations. Use strict equality (`===` and `!==`) to avoid coercion. <a href="https://developer.mozilla.org/en-US/docs/Glossary/Type_coercion" target="_blank">Type Coercion</a></p> - <pre><code class="language-javascript">console.log(typeof 42); // "number" -console.log(typeof "hello"); // "string" -console.log(typeof true); // "boolean" -console.log(typeof undefined); // "undefined" -console.log(typeof null); // "object" (quirk) -console.log(typeof {}); // "object" -console.log(typeof []); // "object" (arrays are objects) -console.log(typeof function(){}); // "function" (functions are objects) - -console.log('5' == 5); // true (coercion) -console.log('5' === 5); // false (strict equality)</code></pre> + <h6>Other Control Statements</h6> + <ul> + <li><strong>`break`</strong>: Exits the current loop or switch statement.</li> + <li><strong>`continue`</strong>: Skips the rest of the current loop iteration and proceeds to the next.</li> + <li><strong>`try...catch...finally`</strong>: Handles errors (exceptions). `try` block contains code that might throw, `catch` handles the error, `finally` always executes (optional). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch" target="_blank">try...catch</a></li> + </ul> + <pre><code class="language-javascript">// for...of example +const colors = ['red', 'green', 'blue']; +for (const color of colors) { + console.log(color); // red, green, blue +} + +// for...in example (use with caution on objects) +const car = { make: 'Toyota', model: 'Camry' }; +for (const prop in car) { + if (Object.hasOwn(car, prop)) { // Important check! + console.log(`${prop}: ${car[prop]}`); // make: Toyota, model: Camry + } +} +</code></pre> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-core" id="card-js-functions"> + <div class="info-card card-core" id="card-js-functions"> <!-- Enhanced --> <div class="card-body"> <h5><i class="bi bi-braces" aria-hidden="true"></i> Functions</h5> <div class="card-content-wrapper"> - <p class="summary">Reusable blocks of code. Defined using declarations or expressions. Understand scope, <span class="term" data-bs-toggle="tooltip" title="Function remembers its lexical scope even when executed outside that scope.">closures</span>, and the <span class="term" data-bs-toggle="tooltip" title="Execution context, value depends on how the function is called.">`this`</span> keyword. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions" target="_blank">MDN Functions</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsFunc" aria-expanded="false" aria-controls="collapseJsFunc"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Reusable code blocks. Defined as declarations or expressions. Understand scope, <span class="term">closures</span>, <span class="term">`this`</span> binding, parameters (default/rest). First-class citizens. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Functions" target="_blank">MDN Functions</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsFunc" aria-expanded="false" aria-controls="collapseJsFunc"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsFunc"> - <h6>Key Concepts</h6> + <h6>Defining Functions</h6> + <ul> + <li><strong>Declaration:</strong> `function name(...) { ... }` (Hoisted).</li> + <li><strong>Expression:</strong> `const name = function(...) { ... };` (Variable hoisted, function not).</li> + <li><strong>Arrow Function (ES6):</strong> `const name = (...) => { ... };` (Concise, lexical `this`).</li> + <li><strong>Named Function Expression:</strong> `const name = function innerName(...) { ... };` (Name available inside).</li> + <li><strong>Immediately Invoked Function Expression (IIFE):</strong> `(function() { ... })();` (Creates private scope, less common with modules).</li> + </ul> + <h6>Closures</h6> + <p>A function "closes over" its lexical environment (scope where it was created). It remembers and can access variables from its outer scope, even after the outer function has finished executing. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures" target="_blank">MDN Closures</a></p> + <pre><code class="language-javascript">function createCounter() { + let count = 0; // Variable in outer scope + return function() { // Inner function forms a closure + count++; + console.log(count); + return count; + }; +} +const counter1 = createCounter(); +counter1(); // 1 +counter1(); // 2 +const counter2 = createCounter(); +counter2(); // 1 (independent count) +</code></pre> + <h6>`this` Keyword Binding</h6> + <p>The value of `this` depends on *how* the function is called: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this" target="_blank">MDN `this`</a></p> + <ul> + <li><strong>Global Context:</strong> `window` (browser, non-strict mode) or `undefined` (strict mode).</li> + <li><strong>Method Invocation:</strong> `object.method()` sets `this` to `object`.</li> + <li><strong>Constructor Invocation:</strong> `new MyClass()` sets `this` to the newly created instance inside the constructor.</li> + <li><strong>Explicit Binding:</strong> `func.call(thisArg, ...args)`, `func.apply(thisArg, [argsArray])`, `func.bind(thisArg)` (returns new function with fixed `this`).</li> + <li><strong>Arrow Functions:</strong> Inherit `this` lexically from the surrounding scope where they are defined. They do *not* have their own `this` binding.</li> + </ul> + <h6>Parameters</h6> <ul> - <li><strong>Declaration:</strong> `function myFunction() { ... }` (Hoisted)</li> - <li><strong>Expression:</strong> `const myFunction = function() { ... };` (Not fully hoisted)</li> - <li><strong>Parameters & Arguments:</strong> Inputs to functions.</li> - <li><strong>Return Value:</strong> Output using `return` keyword (defaults to `undefined`).</li> - <li><strong>Closures:</strong> A function bundled with references to its surrounding state (lexical environment). Allows accessing outer scope variables even after the outer function has finished. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures" target="_blank">Closures</a></li> - <li><strong>`this` Keyword:</strong> Context object. Behavior depends on invocation: global object (sloppy mode), `undefined` (strict mode), object in method calls, new instance with `new`, explicitly set via `call`/`apply`/`bind`. Arrow functions inherit `this` lexically. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this" target="_blank">`this` Keyword</a></li> <li><strong>Default Parameters (ES6):</strong> `function greet(name = 'Guest') { ... }`</li> - <li><strong>Rest Parameters (ES6):</strong> `function sum(...numbers) { ... }` (collects remaining arguments into an array)</li> + <li><strong>Rest Parameters (ES6):</strong> `function sum(...numbers) { ... }` (collects arguments into an array).</li> + <li><strong>`arguments` object:</strong> (Legacy, avoid in ES6+) Array-like object containing all passed arguments (not available in arrow functions).</li> </ul> - <p><em>More examples on 'this' and closures needed here.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-core" id="card-js-arrays"> + <div class="info-card card-core" id="card-js-arrays"> <!-- Enhanced --> <div class="card-body"> <h5><i class="bi bi-list-ol" aria-hidden="true"></i> Arrays</h5> <div class="card-content-wrapper"> - <p class="summary">Ordered lists of values. Access elements via index. Rich set of built-in methods for iteration, mutation, etc. Use <span class="term" data-bs-toggle="tooltip" title="Syntax like ...myArray to expand array elements.">spread syntax (`...`)</span>. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array" target="_blank">MDN Array</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsArr" aria-expanded="false" aria-controls="collapseJsArr"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Ordered lists of values (any type). Zero-indexed. Rich method set for iteration (`map`, `filter`, `reduce`), mutation (`push`, `splice`), etc. Use spread (`...`). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array" target="_blank">MDN Array</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsArr" aria-expanded="false" aria-controls="collapseJsArr"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsArr"> - <h6>Common Methods</h6> + <h6>Creating & Accessing</h6> + <pre><code class="language-javascript">const empty = []; +const items = [1, 'two', { three: 3 }, [4]]; +console.log(items[1]); // 'two' +console.log(items.length); // 4 +</code></pre> + <h6>Common Iteration Methods</h6> <ul> - <li><strong>Iteration:</strong> `forEach()`, `map()`, `filter()`, `reduce()`, `find()`, `findIndex()`, `some()`, `every()`</li> - <li><strong>Mutation:</strong> `push()`, `pop()`, `shift()`, `unshift()`, `splice()`, `sort()`, `reverse()`</li> - <li><strong>Access/Copying:</strong> `slice()`, `concat()`, `includes()`, `indexOf()`, `join()`</li> + <li><strong>`forEach(callback(value, index, array))`</strong>: Executes callback for each element.</li> + <li><strong>`map(callback(value, index, array))`</strong>: Creates a *new* array with results of calling callback on every element.</li> + <li><strong>`filter(callback(value, index, array))`</strong>: Creates a *new* array with elements that pass the callback's test (return true).</li> + <li><strong>`reduce(callback(accumulator, currentValue, index, array), initialValue?)`</strong>: Executes callback on each element, resulting in a single output value (the accumulator).</li> + <li><strong>`find(callback(value, index, array))`</strong>: Returns the *first* element that passes the test.</li> + <li><strong>`findIndex(callback(value, index, array))`</strong>: Returns the *index* of the first element that passes the test.</li> + <li><strong>`some(callback(value, index, array))`</strong>: Checks if *at least one* element passes the test.</li> + <li><strong>`every(callback(value, index, array))`</strong>: Checks if *all* elements pass the test.</li> </ul> - <h6>Spread Syntax (`...`)</h6> - <p>Expands array elements where multiple elements/arguments are expected.</p> - <pre><code class="language-javascript">const arr1 = [1, 2]; -const arr2 = [3, 4]; -const combined = [...arr1, ...arr2]; // [1, 2, 3, 4] -const copy = [...arr1]; // Creates a shallow copy - -function sumNumbers(a, b, c) { return a + b + c; } -const nums = [10, 20, 30]; -console.log(sumNumbers(...nums)); // 60 + <h6>Mutation Methods</h6> + <ul> + <li>`push(item1, ...)` / `pop()`: Add/remove from end.</li> + <li>`unshift(item1, ...)` / `shift()`: Add/remove from beginning.</li> + <li>`splice(start, deleteCount?, item1?, ...)`: Remove/replace elements.</li> + <li>`sort(compareFn?)` / `reverse()`: Sort/reverse in place.</li> + </ul> + <h6>Other Useful Methods</h6> + <ul> + <li>`slice(start?, end?)`: Returns a shallow copy of a portion.</li> + <li>`concat(arr1, ...)`: Returns a new array merging arrays.</li> + <li>`includes(value, fromIndex?)`: Checks if value exists.</li> + <li>`indexOf(value, fromIndex?)` / `lastIndexOf()`: Find index of value.</li> + <li>`join(separator?)`: Join elements into a string.</li> + <li>`Array.isArray(value)`: Check if value is an array.</li> + </ul> + <pre><code class="language-javascript">// Map, Filter, Reduce Example +const numbers = [1, 2, 3, 4, 5]; +const doubled = numbers.map(n => n * 2); // [2, 4, 6, 8, 10] +const evens = numbers.filter(n => n % 2 === 0); // [2, 4] +const sum = numbers.reduce((acc, curr) => acc + curr, 0); // 15 </code></pre> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-core" id="card-js-objects"> + <div class="info-card card-core" id="card-js-objects"> <!-- Enhanced --> <div class="card-body"> <h5><i class="bi bi-diagram-3" aria-hidden="true"></i> Objects & Prototypes</h5> <div class="card-content-wrapper"> - <p class="summary">Collections of key-value pairs (properties). JS uses <span class="term" data-bs-toggle="tooltip" title="Objects inherit properties/methods from other objects.">prototypal inheritance</span>. Access properties via dot or bracket notation. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects" target="_blank">MDN Objects</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsObjects" aria-expanded="false" aria-controls="collapseJsObjects"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Unordered collections of key-value pairs. JS uses <span class="term">prototypal inheritance</span>. Access properties via dot (`.`) or bracket (`[]`) notation. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects" target="_blank">MDN Objects</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsObjects" aria-expanded="false" aria-controls="collapseJsObjects"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsObjects"> - <h6>Key Concepts</h6> + <h6>Creating & Accessing</h6> + <pre><code class="language-javascript">const person = { + firstName: 'Ada', + 'last-name': 'Lovelace', // Use quotes for keys with special chars + age: 36, + greet: function() { // Method (pre-ES6) + console.log(`Hello, I'm ${this.firstName}`); + }, + sayHi() { // Method shorthand (ES6+) + console.log('Hi!'); + } +}; + +console.log(person.firstName); // Ada +console.log(person['last-name']); // Lovelace (Bracket notation needed) +person.greet(); // Hello, I'm Ada +</code></pre> + <h6>Object Methods</h6> <ul> - <li><strong>Literals:</strong> `const obj = { key: 'value', method() { return this.key; } };`</li> - <li><strong>Property Access:</strong> `obj.key` or `obj['key']`. Bracket notation for dynamic keys.</li> - <li><strong>`Object` Methods:</strong> `Object.keys()`, `Object.values()`, `Object.entries()`, `Object.assign()`, `Object.create()`.</li> - <li><strong>Prototypal Inheritance:</strong> Each object has a prototype object from which it inherits properties. The chain ends with `null`. `Object.getPrototypeOf()` and `__proto__` (legacy). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain" target="_blank">Prototype Chain</a></li> + <li><strong>`Object.keys(obj)`</strong>: Returns array of own property keys.</li> + <li><strong>`Object.values(obj)`</strong>: Returns array of own property values.</li> + <li><strong>`Object.entries(obj)`</strong>: Returns array of `[key, value]` pairs.</li> + <li><strong>`Object.assign(target, ...sources)`</strong>: Copies properties from sources to target (shallow copy).</li> + <li><strong>`Object.create(proto, propertiesObject?)`</strong>: Creates a new object with the specified prototype object and properties.</li> + <li><strong>`Object.hasOwn(obj, prop)` (ES2022)</strong> / `obj.hasOwnProperty(prop)` (older): Checks if object has own property (not inherited).</li> + <li><strong>`Object.freeze(obj)`</strong>: Prevents modifications (shallow).</li> </ul> - <p><em>ES6 Classes provide syntactic sugar over this.</em></p> + <h6>Prototypal Inheritance</h6> + <p>Objects inherit properties from their prototype (`[[Prototype]]`). Lookups follow the prototype chain until the property is found or the chain ends (`null`). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain" target="_blank">Prototype Chain</a></p> + <pre><code class="language-javascript">// Using Object.create for inheritance +const animalPrototype = { + speak() { console.log(`${this.name} makes a noise.`); } +}; + +const dog = Object.create(animalPrototype); +dog.name = 'Buddy'; +dog.bark = function() { console.log('Woof!'); }; + +dog.speak(); // Buddy makes a noise. (Inherited) +dog.bark(); // Woof! + +console.log(Object.getPrototypeOf(dog) === animalPrototype); // true + +// ES6 Class equivalent (syntax sugar) +class Animal { speak() { console.log(`${this.name} makes a noise.`); } } +class Dog extends Animal { constructor(name){ super(); this.name = name; } bark() { console.log('Woof!'); } } +const buddy = new Dog('Buddy'); +buddy.speak(); +</code></pre> </div> </div> </div> @@ -567,296 +731,493 @@ console.log(sumNumbers(...nums)); // 60 <div class="row"> <div class="col-lg-4 col-md-6"> <div class="info-card card-modern" id="card-js-arrow-func"> - <div class="card-body"> - <h5><i class="bi bi-arrow-right-short" aria-hidden="true" data-bs-toggle="tooltip" title="Arrow Function Icon"></i> Arrow Functions <span class="version-tag">ES6+</span></h5> + <div class="card-body"> + <h5><i class="bi bi-arrow-right-short" aria-hidden="true"></i> Arrow Functions <span class="version-tag">ES6+</span></h5> <div class="card-content-wrapper"> - <p class="summary">Concise syntax for writing functions. Importantly, they do not have their own <span class="term" data-bs-toggle="tooltip" title="Arrow functions inherit 'this' from the surrounding (lexical) scope.">`this`</span> context; they inherit it. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions" target="_blank" rel="noopener noreferrer">MDN Arrow Functions</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsArrowFunc" aria-expanded="false" aria-controls="collapseJsArrowFunc"> - Details <i class="bi bi-chevron-down" aria-hidden="true"></i> - </button> + <p class="summary">Concise syntax for functions. Lexically binds <span class="term">`this`</span> (inherits from surrounding scope). No `arguments` object. Not suitable for methods needing own `this` or constructors. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions" target="_blank">MDN Arrow Functions</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsArrowFunc" aria-expanded="false" aria-controls="collapseJsArrowFunc"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsArrowFunc"> - <h6>Syntax</h6> - <ul> - <li><strong>Single parameter:</strong> `param => expression` (implicit return)</li> - <li><strong>Multiple parameters:</strong> `(param1, param2) => expression`</li> - <li><strong>No parameters:</strong> `() => expression`</li> - <li><strong>Block body:</strong> `(param1, param2) => { /* statements */ return value; }` (explicit `return` needed)</li> - <li><strong>Object literal return:</strong> `() => ({ key: 'value' })` (wrap in parentheses)</li> - </ul> + <h6>Syntax Examples</h6> + <pre><code class="language-javascript">// Implicit return (single expression) +const double = x => x * 2; + +// Multiple parameters +const sum = (a, b) => a + b; + +// Block body (explicit return needed) +const process = (x, y) => { + const result = x + y * 2; + return result; +}; + +// Returning object literal +const createObj = (id, value) => ({ id: id, value: value }); +</code></pre> <h6>Lexical `this`</h6> - <p>Arrow functions capture the `this` value of the enclosing execution context. They are often useful in callbacks (like `setTimeout` or event listeners) where traditional functions might lose the intended `this`.</p> - <pre><code class="language-javascript">// Traditional function losing 'this' -function Counter() { - this.count = 0; - // Using .bind(this) or assigning this to a variable (self = this) was common - setInterval(function() { - // 'this' here is likely the window or undefined (strict mode) - // this.count++; // Fails or modifies global count - }.bind(this), 1000); // Or use .bind(this) + <p>Crucial benefit: Arrow functions do not create their own `this` context. They inherit `this` from the enclosing scope, making them ideal for callbacks in methods or asynchronous code where traditional functions might lose context.</p> + <pre><code class="language-javascript">const myObj = { + value: 42, + getValueRegular: function() { + setTimeout(function() { + // 'this' here is NOT myObj (it's window or undefined) + // console.log(this.value); // Error or undefined + }, 100); + }, + getValueArrow: function() { + setTimeout(() => { + // 'this' here IS myObj because arrow inherits from getValueArrow's scope + console.log(this.value); // 42 + }, 100); + } +}; +myObj.getValueRegular(); +myObj.getValueArrow(); +</code></pre> + <h6>Limitations</h6> + <ul> + <li>Cannot be used as constructors (`new` throws error).</li> + <li>Do not have their own `arguments` object (use rest parameters `...args` instead).</li> + <li>Not suitable for object methods that rely on dynamic `this` binding (use regular function syntax instead).</li> + <li>No `prototype` property.</li> + </ul> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-modern" id="card-js-classes"> <!-- Updated --> + <div class="card-body"> + <h5><i class="bi bi-building" aria-hidden="true"></i> Classes <span class="version-tag">ES6+</span></h5> + <div class="card-content-wrapper"> + <p class="summary">Syntactic sugar over prototypal inheritance. Provides `class`, `constructor`, `extends`, `super`, static methods, getters/setters for cleaner object creation and inheritance. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes" target="_blank">MDN Classes</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsClasses" aria-expanded="false" aria-controls="collapseJsClasses"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseJsClasses"> + <h6>Defining Classes & Inheritance</h6> + <pre><code class="language-javascript">class Vehicle { + constructor(make) { + this.make = make; + this._speed = 0; // Convention for "private" backing field + } + + accelerate() { this._speed += 10; } + brake() { this._speed -= 5; } + + // Getter + get speed() { return this._speed; } + + // Static method (called on class, not instance) + static info() { console.log('This is a Vehicle class.'); } } -// Arrow function preserving 'this' -function CounterFixed() { - this.count = 0; - setInterval(() => { - // 'this' here is the CounterFixed instance - this.count++; - console.log(this.count); - }, 1000); +class Car extends Vehicle { + constructor(make, model) { + super(make); // Call parent constructor is required + this.model = model; + } + + // Override parent method + accelerate() { + super.accelerate(); // Call parent method + this._speed += 5; // Add extra acceleration + console.log(`${this.make} ${this.model} accelerating to ${this.speed}`); + } } -// const c = new CounterFixed();</code></pre> - <h6>Limitations</h6> - <p>Cannot be used as constructors (`new`). Do not have their own `arguments` object (use rest parameters `...args` instead). Not suitable for object methods that need their own `this` context pointing to the object itself.</p> + +Vehicle.info(); // This is a Vehicle class. +const myCar = new Car('Toyota', 'Corolla'); +myCar.accelerate(); // Toyota Corolla accelerating to 15 +console.log(myCar.speed); // 15 (using getter) +</code></pre> + <h6>Key Features</h6> + <ul> + <li><strong>`constructor` method:</strong> Initializes object instance. Only one per class.</li> + <li><strong>`extends` keyword:</strong> Sets up prototype chain for inheritance.</li> + <li><strong>`super` keyword:</strong> Calls parent class constructor (`super()`) or methods (`super.methodName()`).</li> + <li><strong>Static methods/properties:</strong> Belong to the class itself, not instances. Accessed via `ClassName.staticMember`.</li> + <li><strong>Getters & Setters:</strong> Define computed properties using `get propName()` and `set propName(value)`.</li> + <li><strong>Public/Private Fields (Experimental):</strong> `#field` syntax for private instance fields (check browser/Node support).</li> + </ul> + <p><em>Classes are still based on prototypes; they don't change the underlying inheritance model.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-modern" id="card-js-promises"> + <div class="info-card card-modern" id="card-js-modules"> <!-- Updated --> + <div class="card-body"> + <h5><i class="bi bi-box-arrow-in-down" aria-hidden="true"></i> Modules (ESM) <span class="version-tag">ES6+</span></h5> + <div class="card-content-wrapper"> + <p class="summary">Standard JS module system. Use <span class="term">`import`</span> / <span class="term">`export`</span> (named or default) for code organization, reusability, and dependency management. Statically analyzed. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules" target="_blank">MDN Modules</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsModules" aria-expanded="false" aria-controls="collapseJsModules"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseJsModules"> + <h6>Exporting (from `utils.js`)</h6> + <pre><code class="language-javascript">// Named exports (multiple possible) +export const apiKey = 'abc123xyz'; +export function calculate(a, b) { return a + b; } + +// Exporting existing variables +const SECRET_CODE = 42; +export { SECRET_CODE }; // Can rename: export { SECRET_CODE as CODE }; + +// Default export (only ONE per module) +export default class User { + constructor(name) { this.name = name; } +} +</code></pre> + <h6>Importing (into `main.js`)</h6> + <pre><code class="language-javascript">// Import named exports (must use exact names or aliases) +import { apiKey, calculate as calc } from './utils.js'; + +// Import default export (can use any name) +import Person from './utils.js'; // Assuming User class was default export + +// Import namespace (all named exports as properties of an object) +import * as Utils from './utils.js'; + +// Import only for side effects (rare, runs the module code) +import './sideEffectsOnly.js'; + +console.log(apiKey); +console.log(calc(5, 3)); // Using alias 'calc' +const user = new Person('Bob'); +console.log(Utils.apiKey); // Access via namespace +</code></pre> + <h6>Usage & Characteristics</h6> + <ul> + <li><strong>Static Structure:</strong> Imports/exports must be top-level (cannot be conditional). Allows build tools to analyze dependencies.</li> + <li><strong>Strict Mode:</strong> Modules always execute in strict mode.</li> + <li><strong>Scope:</strong> Each module has its own top-level scope.</li> + <li><strong>Browsers:</strong> Use `<script type="module" src="main.js"></script>`.</li> + <li><strong>Node.js:</strong> Use `.mjs` extension or `"type": "module"` in `package.json`. Interoperability with CommonJS (`require`) exists but has nuances.</li> + <li><strong>Dynamic `import()`:</strong> Function-like `import('./module.js')` returns a Promise, allowing conditional/lazy loading of modules.</li> + </ul> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-modern" id="card-js-promises"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-hourglass-split" aria-hidden="true"></i> Promises <span class="version-tag">ES6+</span></h5> <div class="card-content-wrapper"> - <p class="summary">Object representing the eventual completion (or failure) of an asynchronous operation. Enables chaining (`.then()`, `.catch()`). <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank">MDN Promise</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsPromise" aria-expanded="false" aria-controls="collapseJsPromise"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Represents eventual result (or failure) of an async operation. Enables cleaner async code via chaining (`.then`, `.catch`, `.finally`). Foundation for `async/await`. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank">MDN Promise</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsPromise" aria-expanded="false" aria-controls="collapseJsPromise"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsPromise"> - <h6>States</h6> + <h6>States & Flow</h6> <ul> - <li><strong>Pending:</strong> Initial state, neither fulfilled nor rejected.</li> - <li><strong>Fulfilled:</strong> Operation completed successfully.</li> - <li><strong>Rejected:</strong> Operation failed.</li> + <li><strong>Pending:</strong> Initial state. Operation not yet completed.</li> + <li><strong>Fulfilled:</strong> Operation completed successfully, resolves with a value.</li> + <li><strong>Rejected:</strong> Operation failed, rejects with an error/reason.</li> </ul> - <h6>Chaining</h6> - <pre><code class="language-javascript">fetch('/api/data') // fetch returns a Promise - .then(response => { - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); + <p>Promises are immutable once settled (fulfilled or rejected).</p> + <h6>Creating Promises (Less common now with `async/await` and Promise-based APIs)</h6> + <pre><code class="language-javascript">const myPromise = new Promise((resolve, reject) => { + // Asynchronous operation (e.g., setTimeout, network request) + setTimeout(() => { + const success = Math.random() > 0.5; + if (success) { + resolve("Operation succeeded!"); // Fulfills the promise + } else { + reject(new Error("Operation failed!")); // Rejects the promise } - return response.json(); // .json() also returns a Promise + }, 1000); +}); +</code></pre> + <h6>Consuming Promises</h6> + <pre><code class="language-javascript">myPromise + .then(result => { // Handles fulfillment + console.log("Success:", result); + return "Processed: " + result; // Value passed to next .then }) - .then(data => { - console.log('Data received:', data); + .then(processedResult => { + console.log("Next step:", processedResult); }) - .catch(error => { - console.error('Fetch failed:', error); + .catch(error => { // Handles rejection from promise or any previous .then + console.error("Error:", error.message); }) - .finally(() => { - console.log('Fetch attempt finished.'); + .finally(() => { // Executes regardless of success or failure + console.log("Promise settled."); }); </code></pre> - <h6>Static Methods</h6> + <h6>Common Static Methods</h6> <ul> - <li><strong>`Promise.all(iterable)`:</strong> Fulfilled when all promises in iterable fulfill. Rejects if any reject.</li> - <li><strong>`Promise.race(iterable)`:</strong> Settled (fulfilled or rejected) as soon as one promise in iterable settles.</li> - <li><strong>`Promise.allSettled(iterable)`:</strong> Fulfilled when all promises settle (regardless of outcome). Result is an array of status objects.</li> - <li><strong>`Promise.resolve(value)`:</strong> Returns a Promise resolved with the given value.</li> - <li><strong>`Promise.reject(reason)`:</strong> Returns a Promise rejected with the given reason.</li> + <li><strong>`Promise.all(iterable)`:</strong> Waits for all promises to fulfill. Rejects immediately if *any* reject. Useful for parallel independent operations.</li> + <li><strong>`Promise.race(iterable)`:</strong> Settles as soon as the *first* promise in the iterable settles (fulfills or rejects).</li> + <li><strong>`Promise.allSettled(iterable)`:</strong> Waits for all promises to settle. Resolves with an array of status objects (`{status: 'fulfilled', value: ...}` or `{status: 'rejected', reason: ...}`). Useful when you need the outcome of all operations, even failures.</li> + <li><strong>`Promise.any(iterable)` (ES2021):</strong> Waits for the *first* promise to fulfill. Rejects only if *all* promises reject.</li> + <li><strong>`Promise.resolve(value)` / `Promise.reject(reason)`:</strong> Create already settled promises.</li> </ul> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-modern" id="card-js-async-await"> + <div class="info-card card-modern" id="card-js-async-await"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-lightning" aria-hidden="true"></i> Async/Await <span class="version-tag">ES2017+</span></h5> <div class="card-content-wrapper"> - <p class="summary">Syntactic sugar built on Promises, allowing asynchronous code to be written more like synchronous code. Use <span class="term">`async`</span> for functions and <span class="term">`await`</span> to pause for Promises. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function" target="_blank">MDN Async Function</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsAsync" aria-expanded="false" aria-controls="collapseJsAsync"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Syntactic sugar over Promises. Write asynchronous code that looks synchronous. `async` functions return Promises. `await` pauses execution until a Promise settles. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function" target="_blank">MDN Async Function</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsAsync" aria-expanded="false" aria-controls="collapseJsAsync"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseJsAsync"> <h6>Usage</h6> <ul> - <li><strong>`async` Keyword:</strong> Placed before a function declaration makes it automatically return a Promise.</li> - <li><strong>`await` Keyword:</strong> Can only be used inside an `async` function. Pauses execution until the awaited Promise settles. If fulfilled, returns the resolved value. If rejected, throws the rejection reason.</li> + <li><strong>`async` Keyword:</strong> Before `function`, arrow function, or method definition. Makes the function implicitly return a Promise. The Promise resolves with the function's return value or rejects if an error is thrown.</li> + <li><strong>`await` Keyword:</strong> *Only usable inside `async` functions*. Pauses execution until the awaited `Promise` settles. If fulfilled, `await` returns the resolved value. If rejected, `await` throws the rejection error (can be caught by `try...catch`).</li> </ul> - <h6>Example</h6> - <pre><code class="language-javascript">async function fetchData() { - console.log('Fetching data...'); + <h6>Example (Fetch with Async/Await)</h6> + <pre><code class="language-javascript">async function getUserData(userId) { + console.log(`Fetching data for user ${userId}...`); try { - const response = await fetch('/api/data'); // Pauses here + const response = await fetch(`/api/users/${userId}`); // Pause until fetch promise settles if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } - const data = await response.json(); // Pauses here + const data = await response.json(); // Pause until json() promise settles console.log('Data received:', data); - return data; + return data; // This value fulfills the promise returned by getUserData } catch (error) { console.error('Fetch failed:', error); - // Handle error or re-throw + // Handle error or re-throw to reject the promise returned by getUserData throw error; - } finally { - console.log('Fetch attempt finished.'); } } -// Call the async function -fetchData() - .then(result => console.log('Async function finished with:', result)) - .catch(err => console.log('Async function caught error:', err)); +// Calling the async function +async function displayUser() { + try { + const user = await getUserData(123); + console.log(`Displaying user: ${user.name}`); + } catch(err) { + console.log('Could not display user data.'); + } +} +displayUser(); </code></pre> - <h6>Parallel Operations</h6> - <p>Use `Promise.all()` with `await` to run multiple async operations concurrently.</p> + <h6>Parallel Operations with `await`</h6> + <p>Use `Promise.all()` with `await` to wait for multiple promises concurrently.</p> <pre><code class="language-javascript">async function fetchMultiple() { try { - const [userData, postsData] = await Promise.all([ - fetch('/api/user').then(res => res.json()), - fetch('/api/posts').then(res => res.json()) - ]); + console.log('Fetching user and posts...'); + // Start both fetches nearly simultaneously + const userPromise = fetch('/api/user').then(res => res.json()); + const postsPromise = fetch('/api/posts').then(res => res.json()); + + // Wait for both promises to complete + const [userData, postsData] = await Promise.all([userPromise, postsPromise]); + console.log('User:', userData); console.log('Posts:', postsData); } catch (error) { console.error('Failed fetching multiple:', error); } } +fetchMultiple(); </code></pre> </div> </div> </div> - <div class="col-lg-4 col-md-6"> - <div class="info-card card-modern" id="card-js-modules"> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-modern" id="card-js-destructuring"> <!-- Updated --> <div class="card-body"> - <h5><i class="bi bi-box-arrow-in-down" aria-hidden="true"></i> Modules (ESM) <span class="version-tag">ES6+</span></h5> + <h5><i class="bi bi-arrows-angle-contract" aria-hidden="true"></i> Destructuring <span class="version-tag">ES6+</span></h5> <div class="card-content-wrapper"> - <p class="summary">Standard module system for JS. Use <span class="term">`import`</span> to bring in functionality and <span class="term">`export`</span> to make it available. Enables code organization and reusability. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules" target="_blank">MDN Modules</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsModules" aria-expanded="false" aria-controls="collapseJsModules"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Unpack values from arrays or properties from objects into variables. Cleaner syntax for accessing data and function parameters. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment" target="_blank">MDN Destructuring</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsDestructuring" aria-expanded="false" aria-controls="collapseJsDestructuring"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseJsModules"> - <h6>Exporting</h6> - <pre><code class="language-javascript">// utils.js -export const PI = 3.14159; + <div class="collapse collapse-content" id="collapseJsDestructuring"> + <h6>Array Destructuring</h6> + <pre><code class="language-javascript">const scores = [100, 85, 92, 78]; -export function double(n) { - return n * 2; -} +// Basic assignment +const [first, second] = scores; // first=100, second=85 -export default function greet(name) { // Only one default export per module - console.log(`Hello, ${name}!`); -} +// Skip elements +const [winner, , thirdPlace] = scores; // winner=100, thirdPlace=92 + +// Rest syntax +const [champion, ...others] = scores; // champion=100, others=[85, 92, 78] + +// Default values +const [a, b, c, d, e = 50] = scores; // e=50 (default used if element missing) + +// Swapping variables +let x = 1, y = 2; +[x, y] = [y, x]; // x=2, y=1 </code></pre> - <h6>Importing</h6> - <pre><code class="language-javascript">// main.js -import { PI, double } from './utils.js'; // Named imports -import sayHello from './utils.js'; // Default import (can rename) -// OR import * as Utils from './utils.js'; // Namespace import - -console.log(PI); // 3.14159 -console.log(double(5)); // 10 -sayHello('World'); // Logs: Hello, World! -// Utils.greet('Again'); // Using namespace import + <h6>Object Destructuring</h6> + <pre><code class="language-javascript">const config = { host: 'localhost', port: 8080, enabled: true }; + +// Basic assignment (variable name must match key) +const { host, port } = config; // host='localhost', port=8080 + +// Assign to different variable names +const { host: serverHost, port: serverPort } = config; // serverHost='localhost' + +// Default values +const { timeout = 5000, enabled } = config; // timeout=5000 + +// Nested destructuring +const data = { user: { id: 1, name: 'Eve' }, status: 'active' }; +const { status, user: { name: userName } } = data; // status='active', userName='Eve' + +// Rest syntax +const { host: h, ...restConfig } = config; // h='localhost', restConfig={ port: 8080, enabled: true } +</code></pre> + <h6>Function Parameters</h6> + <p>Very common for unpacking options objects or props in frameworks.</p> + <pre><code class="language-javascript">function createUser({ name, email, role = 'user' }) { + console.log(`Creating ${role}: ${name} (${email})`); +} +createUser({ email: '[email protected]', name: 'Test User' }); +// Output: Creating user: Test User ([email protected]) </code></pre> - <h6>Usage Context</h6> - <ul> - <li><strong>Browsers:</strong> Use `<script type="module" src="main.js"></script>`. Handles dependencies automatically.</li> - <li><strong>Node.js:</strong> Use `.mjs` extension or set `"type": "module"` in `package.json`. CommonJS (`require`) still prevalent but ESM is the standard.</li> - </ul> </div> </div> </div> - <div class="col-lg-4 col-md-6"> - <div class="info-card card-modern" id="card-js-classes"> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-modern" id="card-js-template-literals"> <div class="card-body"> - <h5><i class="bi bi-building" aria-hidden="true"></i> Classes <span class="version-tag">ES6+</span></h5> - <div class="card-content-wrapper"> - <p class="summary">Syntactic sugar over JavaScript's prototypal inheritance. Provides a cleaner syntax for creating objects and managing inheritance. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes" target="_blank">MDN Classes</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsClasses" aria-expanded="false" aria-controls="collapseJsClasses"> - Details <i class="bi bi-chevron-down"></i> - </button> + <h5><i class="bi bi-file-text" aria-hidden="true"></i> Template Literals <span class="version-tag">ES6+</span></h5> + <div class="card-content-wrapper"> + <p class="summary">Enhanced string literals using backticks (`` ` ``). Allow embedded expressions (`${expression}`), multiline strings, and tagged templates. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals" target="_blank">MDN Template Literals</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsTemplates" aria-expanded="false" aria-controls="collapseJsTemplates"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseJsClasses"> - <h6>Defining Classes</h6> - <pre><code class="language-javascript">class Animal { - constructor(name) { - this.name = name; - } - - speak() { - console.log(`${this.name} makes a noise.`); - } + <div class="collapse collapse-content" id="collapseJsTemplates"> + <h6>String Interpolation</h6> + <p>Embed expressions directly within the string.</p> + <pre><code class="language-javascript">const name = "World"; +const score = 95; +const message = `Hello, ${name}! Your score is ${score}. (${score >= 90 ? 'Excellent!' : 'Good'})`; +console.log(message); // Hello, World! Your score is 95. (Excellent!) +</code></pre> + <h6>Multiline Strings</h6> + <p>Newlines within backticks are preserved in the string.</p> + <pre><code class="language-javascript">const html = ` +<div> + <h1>Title</h1> + <p>Paragraph text.</p> +</div>`; +console.log(html); +</code></pre> + <h6>Tagged Templates</h6> + <p>Advanced feature where a function (the "tag") processes the template literal parts. Used by libraries like styled-components.</p> + <pre><code class="language-javascript">function highlight(strings, ...values) { + let result = ''; + strings.forEach((str, i) => { + result += str; + if (values[i]) { + result += `<mark>${values[i]}</mark>`; + } + }); + return result; } -class Dog extends Animal { - constructor(name, breed) { - super(name); // Call parent constructor - this.breed = breed; - } +const term = "JavaScript"; +const info = "awesome"; +const tagged = highlight`Learn ${term}, it's ${info}!`; +console.log(tagged); // Learn <mark>JavaScript</mark>, it's <mark>awesome</mark>! +</code></pre> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-modern" id="card-js-optional-chaining"> + <div class="card-body"> + <h5><i class="bi bi-question-circle" aria-hidden="true"></i> Opt. Chaining & Nullish Coalescing <span class="version-tag">ES2020+</span></h5> + <div class="card-content-wrapper"> + <p class="summary">Safely access nested properties with <span class="term">Optional Chaining (`?.`)</span>. Provide defaults for `null` or `undefined` with <span class="term">Nullish Coalescing (`??`)</span>. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining" target="_blank">`?.`</a> | <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator" target="_blank">`??`</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsOptional" aria-expanded="false" aria-controls="collapseJsOptional"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseJsOptional"> + <h6>Optional Chaining (`?.`)</h6> + <p>Stops evaluation and returns `undefined` if the value before `?.` is `null` or `undefined`, preventing errors when accessing properties of potentially non-existent objects.</p> + <pre><code class="language-javascript">const user = { + name: 'Charlie', + // address: { street: '123 Main St' } // address might be missing +}; - speak() { // Override parent method - console.log(`${this.name} barks.`); - } +// Without optional chaining (throws error if address is missing) +// const street = user.address.street; - fetch() { - console.log(`${this.name} fetches the ball.`); - } -} +// With optional chaining +const street = user.address?.street; // undefined if user.address is null/undefined +console.log(street); -const myDog = new Dog('Rex', 'German Shepherd'); -myDog.speak(); // Rex barks. -myDog.fetch(); // Rex fetches the ball. -console.log(myDog.breed); // German Shepherd +// Works with function/method calls too +const adminName = user.adminProfile?.getName?.(); // undefined if adminProfile or getName missing +</code></pre> + <h6>Nullish Coalescing Operator (`??`)</h6> + <p>Logical operator returning the right-hand operand only when the left-hand operand is `null` or `undefined`. Otherwise, returns the left-hand operand. Useful for setting defaults where `0` or `''` (empty string) are valid values (unlike `||` which treats them as falsy).</p> + <pre><code class="language-javascript">const config = { timeout: 0, retries: null }; + +// Using OR (||) - treats 0 as falsy +const timeoutSetting_OR = config.timeout || 5000; // 5000 (Incorrect!) +const retrySetting_OR = config.retries || 3; // 3 + +// Using Nullish Coalescing (??) +const timeoutSetting_NC = config.timeout ?? 5000; // 0 (Correct!) +const retrySetting_NC = config.retries ?? 3; // 3 +const missingSetting_NC = config.missing ?? 'default'; // 'default' + +console.log(`Timeout (||): ${timeoutSetting_OR}, Timeout (??): ${timeoutSetting_NC}`); +console.log(`Retries (||): ${retrySetting_OR}, Retries (??): ${retrySetting_NC}`); +console.log(`Missing (??): ${missingSetting_NC}`); </code></pre> - <h6>Key Features</h6> - <ul> - <li><strong>`constructor` method:</strong> Special method for creating and initializing an object created with a class.</li> - <li><strong>`extends` keyword:</strong> Used for inheritance from a parent class.</li> - <li><strong>`super` keyword:</strong> Used to call corresponding methods of a super class (e.g., `super()` in constructor, `super.methodName()`).</li> - <li><strong>Static methods:</strong> Defined with `static` keyword, called on the class itself, not instances.</li> - <li><strong>Getters & Setters:</strong> Define computed properties.</li> - </ul> - <p><em>Classes are primarily syntactic sugar and do not introduce a new object-oriented inheritance model to JavaScript.</em></p> </div> </div> </div> - <div class="col-lg-4 col-md-6"> - <div class="info-card card-modern" id="card-js-destructuring"> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-modern" id="card-js-map-set"> <div class="card-body"> - <h5><i class="bi bi-arrows-angle-contract" aria-hidden="true"></i> Destructuring <span class="version-tag">ES6+</span></h5> - <div class="card-content-wrapper"> - <p class="summary">Syntax for unpacking values from arrays or properties from objects into distinct variables. Makes code cleaner and more readable. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment" target="_blank">MDN Destructuring</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsDestructuring" aria-expanded="false" aria-controls="collapseJsDestructuring"> - Details <i class="bi bi-chevron-down"></i> - </button> + <h5><i class="bi bi-collection" aria-hidden="true"></i> Map & Set <span class="version-tag">ES6+</span></h5> + <div class="card-content-wrapper"> + <p class="summary"><span class="term">Map</span> holds key-value pairs (any type as key). <span class="term">Set</span> stores unique values (any type). Both iterable. Better alternatives to objects/arrays for certain use cases. <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map" target="_blank">Map</a> | <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set" target="_blank">Set</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseJsMapSet" aria-expanded="false" aria-controls="collapseJsMapSet"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseJsDestructuring"> - <h6>Array Destructuring</h6> - <pre><code class="language-javascript">const fruits = ['apple', 'banana', 'cherry']; -const [first, second, third] = fruits; -console.log(first); // apple - -const [a, , c] = fruits; // Skip elements -console.log(c); // cherry - -const [x, ...rest] = fruits; // Rest syntax -console.log(rest); // ['banana', 'cherry'] + <div class="collapse collapse-content" id="collapseJsMapSet"> + <h6>Map</h6> + <ul> + <li>Ordered key-value pairs. Keys can be any type (objects, functions, etc.).</li> + <li>Methods: `set(key, value)`, `get(key)`, `has(key)`, `delete(key)`, `clear()`, `size`.</li> + <li>Iterable: `keys()`, `values()`, `entries()`, `forEach()`.</li> + </ul> + <pre><code class="language-javascript">const userMap = new Map(); +const user1 = { id: 1 }; +userMap.set(user1, { name: 'Alice', role: 'admin' }); +userMap.set('key2', 'value2'); + +console.log(userMap.get(user1)); // { name: 'Alice', role: 'admin' } +console.log(userMap.size); // 2 +for (const [key, value] of userMap) { console.log(key, value); } </code></pre> - <h6>Object Destructuring</h6> - <pre><code class="language-javascript">const person = { name: 'Alice', age: 30, city: 'New York' }; -const { name, age } = person; -console.log(name); // Alice - -const { name: personName, city } = person; // Rename variables -console.log(personName); // Alice + <h6>Set</h6> + <ul> + <li>Collection of unique values. Order based on insertion.</li> + <li>Methods: `add(value)`, `has(value)`, `delete(value)`, `clear()`, `size`.</li> + <li>Iterable: `values()`, `keys()` (alias for values), `entries()` (`[value, value]`), `forEach()`.</li> + </ul> + <pre><code class="language-javascript">const uniqueNums = new Set([1, 2, 3, 2, 1]); +uniqueNums.add(4); +uniqueNums.add(1); // Ignored, already exists -const { country = 'USA' } = person; // Default values -console.log(country); // USA +console.log(uniqueNums.has(2)); // true +console.log(uniqueNums.size); // 4 +for (const num of uniqueNums) { console.log(num); } // 1, 2, 3, 4 -function greet({ name, age }) { // Destructuring in function parameters - console.log(`Hello ${name}, you are ${age}.`); -} -greet(person); +// Common use case: Remove duplicates from array +const numbers = [5, 6, 5, 7, 6]; +const unique = [...new Set(numbers)]; // [5, 6, 7] </code></pre> - <p>Useful for extracting values, assigning to variables, and in function parameters.</p> </div> </div> </div> @@ -868,360 +1229,672 @@ greet(person); <h2 class="section-title" id="section-browser-title">Browser Environment & Web APIs</h2> <div class="row"> <div class="col-lg-4 col-md-6"> - <div class="info-card card-browser" id="card-browser-dom"> + <div class="info-card card-browser" id="card-browser-dom"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-diagram-2" aria-hidden="true"></i> The DOM</h5> <div class="card-content-wrapper"> - <p class="summary"><span class="term">Document Object Model</span>: A tree-like representation of the HTML document. Allows JS to interact with and manipulate page content, structure, and style. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction" target="_blank">MDN DOM Intro</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserDom" aria-expanded="false" aria-controls="collapseBrowserDom"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary"><span class="term">Document Object Model</span>: API for HTML/XML documents. Represents structure as a node tree. JS interacts via `document` object to manipulate content/style. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction" target="_blank">MDN DOM Intro</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserDom" aria-expanded="false" aria-controls="collapseBrowserDom"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseBrowserDom"> <h6>Key Concepts</h6> <ul> - <li><strong>Tree Structure:</strong> Represents HTML elements as nested nodes. The `document` object is the root.</li> - <li><strong>`document` Object:</strong> Entry point to the DOM for a page (e.g., `document.body`, `document.head`).</li> - <li><strong>Nodes:</strong> Different types represent elements (Element Node), text content (Text Node), attributes (Attribute Node), comments, etc.</li> - <li><strong>Live vs. Static Collections:</strong> Some DOM methods return live collections (update automatically when DOM changes, e.g., `getElementsByTagName`), others static (snapshot, e.g., `querySelectorAll`).</li> + <li><strong>Node Tree:</strong> Represents document structure (elements, text, attributes, comments).</li> + <li><strong>`document` Object:</strong> Root entry point (`document.body`, `document.head`, `document.documentElement`).</li> + <li><strong>Node Types:</strong> `Element`, `Text`, `Attribute`, `Comment`, `Document`, etc.</li> + <li><strong>Traversal:</strong> Navigating the tree (`parentNode`, `childNodes`, `firstChild`, `lastChild`, `nextSibling`, `previousSibling`).</li> + <li><strong>Live vs. Static Collections:</strong> `getElementsByTagName`/`ClassName` return live `HTMLCollection`s (update automatically). `querySelectorAll` returns a static `NodeList`.</li> </ul> + <p>Modern frameworks (React, Vue, etc.) abstract direct DOM manipulation but understanding it is crucial.</p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-browser" id="card-browser-dom-manip"> + <div class="info-card card-browser" id="card-browser-dom-manip"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-pencil-square" aria-hidden="true"></i> DOM Manipulation</h5> <div class="card-content-wrapper"> - <p class="summary">Selecting elements (e.g., `querySelector`, `getElementById`), modifying content (`textContent`, `innerHTML`), attributes (`setAttribute`), styles (`element.style`), and structure (`createElement`, `appendChild`). <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents" target="_blank">MDN Manipulating Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserDomManip" aria-expanded="false" aria-controls="collapseBrowserDomManip"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Selecting elements (`querySelector`), modifying content/attributes/styles, creating/adding/removing elements (`createElement`, `appendChild`, `remove`). <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Client-side_web_APIs/Manipulating_documents" target="_blank">MDN Manipulating Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserDomManip" aria-expanded="false" aria-controls="collapseBrowserDomManip"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseBrowserDomManip"> - <h6>Common Tasks</h6> + <h6>Common Tasks & Methods</h6> <ul> <li><strong>Selecting:</strong> <ul> <li>`document.getElementById('id')`</li> - <li>`document.querySelector('.class')` (first match)</li> - <li>`document.querySelectorAll('tag, .class')` (NodeList)</li> - <li>`document.getElementsByClassName('class')` (HTMLCollection - live)</li> - <li>`document.getElementsByTagName('tag')` (HTMLCollection - live)</li> + <li>`document.querySelector(cssSelector)` (first match)</li> + <li>`document.querySelectorAll(cssSelector)` (static NodeList)</li> + <li>`element.closest(cssSelector)` (finds nearest ancestor)</li> </ul> </li> - <li><strong>Modifying Text:</strong> `element.textContent = 'New text';` (safer, ignores HTML)</li> - <li><strong>Modifying HTML:</strong> `element.innerHTML = '<span>New HTML</span>';` (Use with caution due to XSS risks if content is user-supplied)</li> - <li><strong>Attributes:</strong> `element.setAttribute('href', '#')`, `element.getAttribute('src')`, `element.removeAttribute('disabled')`, `element.hasAttribute('data-custom')`</li> - <li><strong>Classes:</strong> `element.classList.add('active')`, `element.classList.remove('disabled')`, `element.classList.toggle('highlight')`, `element.classList.contains('item')`</li> - <li><strong>Styles:</strong> `element.style.color = 'blue';`, `element.style.display = 'none';` (sets inline styles)</li> - <li><strong>Creating:</strong> `const newDiv = document.createElement('div');`</li> - <li><strong>Appending/Inserting:</strong> `parentElement.appendChild(newChild);`, `parentElement.insertBefore(newChild, referenceChild);`, `element.append(...nodesOrStrings);`, `element.prepend(...nodesOrStrings);`</li> - <li><strong>Removing:</strong> `element.remove();` or `parentElement.removeChild(element);`</li> + <li><strong>Modifying Text/HTML:</strong> `element.textContent` (safer), `element.innerHTML` (parses HTML, potential XSS).</li> + <li><strong>Attributes:</strong> `element.setAttribute()`, `element.getAttribute()`, `element.removeAttribute()`, `element.hasAttribute()`, `element.dataset` (for `data-*` attributes).</li> + <li><strong>Classes:</strong> `element.classList.add()`, `.remove()`, `.toggle()`, `.contains()`.</li> + <li><strong>Styles:</strong> `element.style.propertyName = 'value'` (sets inline styles, `propertyName` is camelCase e.g., `backgroundColor`).</li> + <li><strong>Creating:</strong> `document.createElement('tag')`, `document.createTextNode('text')`.</li> + <li><strong>Adding/Inserting:</strong> `parent.appendChild(child)`, `parent.insertBefore(new, ref)`, `element.append(...nodes)`, `element.prepend(...nodes)`, `element.before(...nodes)`, `element.after(...nodes)`.</li> + <li><strong>Removing:</strong> `element.remove()`.</li> + <li><strong>Dimensions/Position:</strong> `element.getBoundingClientRect()`, `element.offsetWidth`, `offsetHeight`.</li> </ul> + <p>Direct manipulation is less common with frameworks but essential for vanilla JS or specific integration tasks.</p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-browser" id="card-browser-fetch"> + <div class="info-card card-browser" id="card-browser-events"> <!-- Updated --> + <div class="card-body"> + <h5><i class="bi bi-mouse" aria-hidden="true"></i> Event Handling</h5> + <div class="card-content-wrapper"> + <p class="summary">Respond to user interactions or browser events. Use <span class="term">`addEventListener`</span>. Understand event object, bubbling/capturing, `preventDefault`, `stopPropagation`. <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events" target="_blank">MDN Events</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserEvents" aria-expanded="false" aria-controls="collapseBrowserEvents"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseBrowserEvents"> + <h6>Attaching Listeners</h6> + <p>Prefer `addEventListener` over `on<event>` attributes/properties.</p> + <pre><code class="language-javascript">const button = document.querySelector('#myButton'); + +function handleClick(event) { + console.log(`Event type: ${event.type}`); // 'click' + console.log(`Target element:`, event.target); // The button itself + console.log(`Current target:`, event.currentTarget); // Element listener attached to (often same as target) + console.log(`Click position: X=${event.clientX}, Y=${event.clientY}`); + + // Stop default browser action (e.g., link navigation, form submission) + // event.preventDefault(); + + // Stop event from propagating further up or down the DOM tree + // event.stopPropagation(); +} + +// Add listener (Bubbling phase by default) +button.addEventListener('click', handleClick); + +// Add listener (Capturing phase) +// button.addEventListener('click', handleClick, true); +// OR button.addEventListener('click', handleClick, { capture: true }); + +// Add listener that runs only once +// button.addEventListener('click', handleClick, { once: true }); + +// Remove listener (requires the exact same function reference) +// button.removeEventListener('click', handleClick); +</code></pre> + <h6>Event Object Properties</h6> + <p>`type`, `target`, `currentTarget`, `bubbles`, `cancelable`, `timeStamp`, mouse coords (`clientX`, `clientY`, `pageX`, `pageY`), key info (`key`, `code`, `keyCode`), etc.</p> + <h6>Event Phases & Delegation</h6> + <ul> + <li><strong>Capturing Phase:</strong> Down the tree (window -> target).</li> + <li><strong>Target Phase:</strong> At the element.</li> + <li><strong>Bubbling Phase:</strong> Up the tree (target -> window). Default.</li> + <li><strong>Event Delegation:</strong> Attach listener to a parent. Check `event.target` to identify which child triggered the event. Efficient for many child elements or dynamic content.</li> + </ul> + <h6>Common Event Types</h6> + <p>Mouse (`click`, `dblclick`, `mousedown`, `mouseup`, `mouseover`, `mouseout`, `mousemove`), Keyboard (`keydown`, `keyup`, `keypress`), Form (`submit`, `change`, `input`, `focus`, `blur`), Window (`load`, `DOMContentLoaded`, `resize`, `scroll`), Touch (`touchstart`, `touchmove`, `touchend`).</p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-browser" id="card-browser-fetch"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-cloud-download" aria-hidden="true"></i> Fetch API</h5> <div class="card-content-wrapper"> - <p class="summary">Modern interface for making network requests (HTTP). Promise-based. Used to retrieve data from APIs or send data to servers. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch" target="_blank">MDN Using Fetch</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserFetch" aria-expanded="false" aria-controls="collapseBrowserFetch"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Modern interface for network requests (HTTP). Promise-based. Replaces older `XMLHttpRequest`. Handles Request/Response objects. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch" target="_blank">MDN Using Fetch</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserFetch" aria-expanded="false" aria-controls="collapseBrowserFetch"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseBrowserFetch"> - <h6>Basic GET Request</h6> - <pre><code class="language-javascript">fetch('https://api.example.com/users') - .then(response => { - if (!response.ok) { // Check for HTTP errors (4xx, 5xx) - throw new Error(`Network response was not ok: ${response.statusText} (${response.status})`); + <h6>Basic GET Request (Async/Await)</h6> + <pre><code class="language-javascript">async function getUsers() { + try { + const response = await fetch('https://api.example.com/users'); + if (!response.ok) { // Checks for 200-299 status codes + throw new Error(`HTTP error ${response.status}: ${response.statusText}`); } - return response.json(); // Parse JSON body - }) - .then(users => { - console.log('Users:', users); - }) - .catch(error => { - console.error('Fetch error:', error); // Handles network errors and thrown errors - }); + const users = await response.json(); // Parses JSON body + console.log(users); + return users; + } catch (error) { + console.error('Failed to fetch users:', error); + } +} </code></pre> - <h6>POST Request with JSON</h6> - <pre><code class="language-javascript">async function postData(url = '', data = {}) { + <h6>POST Request with Options</h6> + <pre><code class="language-javascript">async function createUser(userData) { try { - const response = await fetch(url, { - method: 'POST', // *GET, POST, PUT, DELETE, etc. + const response = await fetch('https://api.example.com/users', { + method: 'POST', headers: { - 'Content-Type': 'application/json' - // 'Authorization': 'Bearer YOUR_TOKEN_HERE' // Example header + 'Content-Type': 'application/json', + // 'Accept': 'application/json', + // 'Authorization': 'Bearer YOUR_TOKEN' }, - body: JSON.stringify(data) // Body data type must match "Content-Type" header + body: JSON.stringify(userData) }); - if (!response.ok) { - throw new Error(`HTTP error! Status: ${response.status}`); - } - return await response.json(); // Parses JSON response body + if (!response.ok) { throw new Error(`HTTP error ${response.status}`); } + const createdUser = await response.json(); + console.log('User created:', createdUser); + return createdUser; } catch (error) { - console.error('Error posting data:', error); - throw error; + console.error('Failed to create user:', error); } } - -postData('https://api.example.com/users', { name: 'John Doe', job: 'Developer' }) - .then(data => console.log('Success:', data)); +createUser({ name: 'Jane Doe', job: 'Architect' }); </code></pre> <h6>Response Object</h6> - <p>The `Response` object contains status (`.status`, `.statusText`), headers (`.headers`), and methods to read the body (`.json()`, `.text()`, `.blob()`, `.formData()`), which themselves return Promises.</p> - <h6>Request Options</h6> - <p>The second argument to `fetch` is an options object that can include `method`, `headers`, `body`, `mode` (cors, no-cors), `credentials`, `cache`, `signal` (for AbortController), etc.</p> + <p>Provides access to status (`ok`, `status`, `statusText`), headers (`headers` object), and body reading methods (return Promises): `.json()`, `.text()`, `.blob()`, `.formData()`, `.arrayBuffer()`. A Response body can only be read once.</p> + <h6>Request Object & Options</h6> + <p>Can create `Request` objects explicitly. Options include `method`, `headers`, `body`, `mode` (cors, no-cors, same-origin), `credentials` (omit, same-origin, include), `cache`, `signal` (for `AbortController` to cancel requests).</p> + <h6>Error Handling</h6> + <p>`fetch` only rejects on *network errors*. HTTP error statuses (like 404, 500) do *not* cause rejection; check `response.ok` manually.</p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-browser" id="card-browser-storage"> + <div class="card-body"> + <h5><i class="bi bi-hdd" aria-hidden="true"></i> Web Storage</h5> + <div class="card-content-wrapper"> + <p class="summary">APIs for storing key-value pairs locally in the browser. <span class="term">`localStorage`</span> persists after browser close. <span class="term">`sessionStorage`</span> clears when session ends. Synchronous API. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API" target="_blank">MDN Web Storage</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserStorage" aria-expanded="false" aria-controls="collapseBrowserStorage"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseBrowserStorage"> + <h6>API Methods (Same for both)</h6> + <ul> + <li>`setItem(key, value)`: Store data (value is always stored as string).</li> + <li>`getItem(key)`: Retrieve data (returns string or `null`).</li> + <li>`removeItem(key)`: Delete item by key.</li> + <li>`clear()`: Remove all items.</li> + <li>`key(index)`: Get key name by index.</li> + <li>`length`: Number of items stored.</li> + </ul> + <pre><code class="language-javascript">// Using localStorage +localStorage.setItem('username', 'Alice'); +localStorage.setItem('preferences', JSON.stringify({ theme: 'dark', notifications: true })); + +const username = localStorage.getItem('username'); // "Alice" +const prefs = JSON.parse(localStorage.getItem('preferences')); // { theme: 'dark', ... } + +localStorage.removeItem('username'); +// localStorage.clear(); // Clears everything +</code></pre> + <h6>Differences & Considerations</h6> + <ul> + <li><strong>Persistence:</strong> `localStorage` persists until explicitly cleared. `sessionStorage` tied to browser tab/window session.</li> + <li><strong>Scope:</strong> Both scoped to the origin (protocol, host, port).</li> + <li><strong>Capacity:</strong> Typically 5-10MB per origin (browser dependent).</li> + <li><strong>Synchronous:</strong> Operations block the main thread (can impact performance if used heavily).</li> + <li><strong>Data Type:</strong> Stores only strings. Use `JSON.stringify()` and `JSON.parse()` for objects/arrays.</li> + <li><strong>Alternatives:</strong> IndexedDB (async, larger storage, complex), Cookies (sent with HTTP requests, smaller).</li> + </ul> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-browser" id="card-browser-timers"> + <div class="card-body"> + <h5><i class="bi bi-clock" aria-hidden="true"></i> Timers & Animation</h5> + <div class="card-content-wrapper"> + <p class="summary">Schedule code execution. <span class="term">`setTimeout`</span> runs once after delay. <span class="term">`setInterval`</span> runs repeatedly. <span class="term">`requestAnimationFrame`</span> for smooth animations synchronized with display refresh. <a href="https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout" target="_blank">Timers</a> | <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame" target="_blank">rAF</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserTimers" aria-expanded="false" aria-controls="collapseBrowserTimers"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseBrowserTimers"> + <h6>`setTimeout` & `clearTimeout`</h6> + <p>Executes a function or code snippet once after a specified delay (in milliseconds).</p> + <pre><code class="language-javascript">const timeoutId = setTimeout(() => { + console.log('This runs after 2 seconds.'); +}, 2000); + +// To cancel before it runs: +// clearTimeout(timeoutId); +</code></pre> + <h6>`setInterval` & `clearInterval`</h6> + <p>Repeatedly executes a function or code snippet, with a fixed time delay between each call.</p> + <pre><code class="language-javascript">let count = 0; +const intervalId = setInterval(() => { + count++; + console.log(`Interval tick: ${count}`); + if (count >= 5) { + clearInterval(intervalId); // Stop the interval + console.log('Interval stopped.'); + } +}, 1000); +</code></pre> + <h6>`requestAnimationFrame` (rAF)</h6> + <p>Tells the browser you wish to perform an animation. Requests that the browser schedule a repaint and calls your animation function just before the repaint. Optimized for smooth animations, avoids layout thrashing compared to `setTimeout`/`setInterval` for animation loops.</p> + <pre><code class="language-javascript">const element = document.getElementById('animateMe'); +let start; + +function step(timestamp) { + if (!start) start = timestamp; + const elapsed = timestamp - start; + + // Animate based on elapsed time + element.style.transform = `translateX(${Math.min(0.1 * elapsed, 200)}px)`; + + if (elapsed < 2000) { // Continue animation for 2 seconds + requestAnimationFrame(step); + } +} + +requestAnimationFrame(step); // Start the animation loop +</code></pre> + <p><em>Use `cancelAnimationFrame()` to stop an rAF loop.</em></p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-browser" id="card-browser-bom"> + <div class="card-body"> + <h5><i class="bi bi-window" aria-hidden="true"></i> Browser Object Model (BOM)</h5> + <div class="card-content-wrapper"> + <p class="summary">Browser-specific APIs beyond the DOM standard. Includes the global <span class="term">`window`</span> object, <span class="term">`navigator`</span> (browser info), <span class="term">`location`</span> (URL), <span class="term">`history`</span> (navigation). <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window" target="_blank">MDN Window</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserBom" aria-expanded="false" aria-controls="collapseBrowserBom"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseBrowserBom"> + <h6>`window` Object</h6> + <ul> + <li>The global object in browser context.</li> + <li>Provides access to DOM (`window.document`), BOM, timers, console, etc.</li> + <li>Properties like `innerWidth`, `innerHeight`, `screenX`, `screenY`.</li> + <li>Methods like `alert()`, `prompt()`, `confirm()`, `open()`, `close()`, `scroll()`.</li> + </ul> + <h6>`navigator` Object</h6> + <ul> + <li>Information about the browser: `userAgent`, `language`, `platform`, `onLine`.</li> + <li>Access to features like Geolocation (`navigator.geolocation`), Clipboard API (`navigator.clipboard`), Permissions API (`navigator.permissions`).</li> + </ul> + <h6>`location` Object</h6> + <ul> + <li>Information about the current URL: `href`, `protocol`, `host`, `hostname`, `port`, `pathname`, `search`, `hash`.</li> + <li>Methods for navigation: `assign(url)`, `replace(url)`, `reload()`.</li> + </ul> + <h6>`history` Object</h6> + <ul> + <li>Manages session history.</li> + <li>Methods: `back()`, `forward()`, `go(delta)`.</li> + <li>`pushState()` and `replaceState()` allow manipulating history state without full page loads (used by SPA routers).</li> + </ul> + </div> + </div> + </div> + </div> <!-- /.row --> + </div> <!-- /.schema-container --> + + <!-- IV. Frontend Frameworks & Libraries --> + <div class="schema-container section-frameworks" data-section-id="section-frameworks" data-section-name="Frameworks"> + <h2 class="section-title" id="section-frameworks-title">Frontend Frameworks & Libraries</h2> + <div class="row"> + <!-- React Cards --> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-react" id="card-react-overview"> <!-- Updated --> + <div class="card-body"> + <h5><i class="bi bi-gem" aria-hidden="true"></i> React Overview</h5> + <div class="card-content-wrapper"> + <p class="summary">Library for building UIs via <span class="term">Virtual DOM</span> and <span class="term">components</span>. Declarative, uses <span class="term">JSX</span> and <span class="term">Hooks</span> for state/lifecycle in functional components. <a href="https://react.dev/" target="_blank">React Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactOverview" aria-expanded="false" aria-controls="collapseReactOverview"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseReactOverview"> + <h6>Key Concepts</h6> + <ul> + <li><strong>Declarative UI:</strong> Describe *what* the UI should look like based on state, React handles DOM updates.</li> + <li><strong>Component-Based:</strong> Build encapsulated components that manage their own state, compose them to make complex UIs.</li> + <li><strong>Virtual DOM:</strong> In-memory representation of UI. React calculates minimal DOM changes ("diffing") for efficient updates.</li> + <li><strong>JSX:</strong> Syntax extension, looks like HTML but is compiled to JS function calls (`React.createElement`).</li> + <li><strong>Props:</strong> Pass data down from parent to child (read-only).</li> + <li><strong>State:</strong> Data managed within a component that changes over time, triggering re-renders.</li> + <li><strong>Hooks:</strong> Functions (e.g., `useState`, `useEffect`) enabling state and lifecycle features in functional components.</li> + <li><strong>Unidirectional Data Flow:</strong> State flows down (parent to child via props), events flow up (child to parent via callbacks).</li> + </ul> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-react" id="card-react-jsx"> <!-- Updated --> + <div class="card-body"> + <h5><i class="bi bi-filetype-jsx" aria-hidden="true"></i> JSX</h5> + <div class="card-content-wrapper"> + <p class="summary"><span class="term">JavaScript XML</span>: HTML-like syntax in JS. Embed expressions `{}`. Use `className`, `htmlFor`. Transpiled to `React.createElement()`. <a href="https://react.dev/learn/writing-markup-with-jsx" target="_blank">React JSX Intro</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactJsx" aria-expanded="false" aria-controls="collapseReactJsx"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseReactJsx"> + <h6>Key Features & Syntax</h6> + <ul> + <li><strong>Embedding Expressions:</strong> Use curly braces `{}` for any valid JS expression (variables, function calls, ternary operators). E.g., `<h1>{user.name}</h1>`, `<p>Total: {price * quantity}</p>`.</li> + <li><strong>Attributes:</strong> Use camelCase for most HTML attributes (`className`, `tabIndex`, `onClick`, `htmlFor`). Standard HTML attributes (`data-*`, `aria-*`) remain lowercase.</li> + <li><strong>Boolean Attributes:</strong> `{isEnabled}` is shorthand for `isEnabled={true}`. Omitting means `false`.</li> + <li><strong>Style Attribute:</strong> Takes a JS object with camelCased CSS properties: `style={{ color: 'red', backgroundColor: '#eee' }}`.</li> + <li><strong>Root Element:</strong> Components must return a single root element. Use Fragments (`<>...</>` or `<React.Fragment>...</>`) to avoid extra divs.</li> + <li><strong>Self-Closing Tags:</strong> Required for elements without children (`<img ... />`, `<br />`).</li> + <li><strong>Comments:</strong> Use JS block comments within braces: `{/* Comment here */}`.</li> + </ul> + <pre><code class="language-jsx">function UserProfile({ user, isActive }) { + return ( + <div className={`profile ${isActive ? 'active' : ''}`} style={{ border: '1px solid #ccc' }}> + <h2>{user.name}</h2> + <img src={user.avatarUrl} alt={`${user.name}'s avatar`} /> + {user.isAdmin && <span className="badge">Admin</span>} {/* Conditional */} + <label htmlFor="emailInput">Email:</label> {/* Use htmlFor */} + <input id="emailInput" type="email" defaultValue={user.email} readOnly /> + </div> + ); +} +</code></pre> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-react" id="card-react-components"> + <div class="card-body"> + <h5><i class="bi bi-puzzle" aria-hidden="true"></i> Components (React)</h5> + <div class="card-content-wrapper"> + <p class="summary">Reusable UI building blocks. Typically functions returning JSX. Receive data via <span class="term">props</span> (read-only). Manage internal data with <span class="term">state</span> (Hooks). <a href="https://react.dev/learn/your-first-component" target="_blank">React Components</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactComponents" aria-expanded="false" aria-controls="collapseReactComponents"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseReactComponents"> + <h6>Functional Components (Standard)</h6> + <p>Plain JavaScript functions that accept `props` as an argument and return React elements (usually JSX).</p> + <pre><code class="language-jsx">// Simple stateless component receiving props +function Welcome(props) { + return <h1>Hello, {props.name}!</h1>; +} + +// Component using hooks for state +import React, { useState } from 'react'; +function Counter() { + const [count, setCount] = useState(0); + return ( + <div> + <p>You clicked {count} times</p> + <button onClick={() => setCount(count + 1)}>Click me</button> + </div> + ); +} +</code></pre> + <h6>Props (Properties)</h6> + <ul> + <li>Data passed down from parent components.</li> + <li>Read-only within the child component (unidirectional data flow).</li> + <li>Accessed via the `props` object (e.g., `props.userName`) or by destructuring (`function Welcome({ name }) { ... }`).</li> + </ul> + <h6>Composition</h6> + <p>Components can render other components, allowing complex UIs to be built from smaller, reusable pieces.</p> + <pre><code class="language-jsx">function App() { + return ( + <div> + <Welcome name="Sara" /> + <Welcome name="Cahal" /> + <Counter /> + </div> + ); +} +</code></pre> + <h6>Class Components (Legacy)</h6> + <p>Older syntax using ES6 classes extending `React.Component`. Use `this.props` and `this.state`, lifecycle methods (`componentDidMount`, etc.). Less common in modern React, Hooks are preferred.</p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-react" id="card-react-hooks"> <!-- Updated --> + <div class="card-body"> + <h5><i class="bi bi-life-preserver" aria-hidden="true"></i> State & Lifecycle (Hooks) <span class="version-tag">React 16.8+</span></h5> + <div class="card-content-wrapper"> + <p class="summary">Hooks let functional components use state (`useState`), lifecycle features (`useEffect`), context (`useContext`), refs (`useRef`), and more. Rules: Only call at top level, only from React functions. <a href="https://react.dev/reference/react/hooks" target="_blank">React Hooks Reference</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactHooks" aria-expanded="false" aria-controls="collapseReactHooks"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseReactHooks"> + <h6>Core Hooks</h6> + <ul> + <li><strong>`useState(initialState)`:</strong> Declares state variable. Returns `[stateValue, setStateFunction]`. Trigger re-render on state change.</li> + <li><strong>`useEffect(setupFn, dependencies?)`:</strong> Performs side effects (API calls, subscriptions, timers, DOM manipulation). `setupFn` runs after render. Optional cleanup function returned by `setupFn` runs before next effect or unmount. `dependencies` array controls when effect re-runs (`[]`: mount only, `[val]`: when `val` changes, omitted: every render).</li> + <li><strong>`useContext(Context)`:</strong> Reads value from nearest `Context.Provider` above it in the tree. Re-renders when context value changes.</li> + </ul> + <h6>Additional Common Hooks</h6> + <ul> + <li><strong>`useReducer(reducer, initialArg, init?)`:</strong> Alternative to `useState` for complex state logic involving multiple sub-values or when next state depends on previous one.</li> + <li><strong>`useCallback(fn, dependencies)`:</strong> Returns a memoized version of the callback function that only changes if dependencies change. Useful for optimizing child components relying on reference equality.</li> + <li><strong>`useMemo(computeFn, dependencies)`:</strong> Returns a memoized value. Runs `computeFn` only when dependencies change. Useful for expensive calculations.</li> + <li><strong>`useRef(initialValue)`:</strong> Returns a mutable `ref` object whose `.current` property persists across renders without causing re-renders. Used to access DOM nodes or store mutable instance variables.</li> + <li><strong>`useLayoutEffect(setupFn, dependencies?)`:</strong> Similar to `useEffect`, but fires synchronously *after* all DOM mutations. Use for reading layout from the DOM and synchronously re-rendering. Prefer `useEffect` when possible.</li> + </ul> + <p><em>See individual Hook cards or React docs for detailed examples.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-browser" id="card-browser-events"> + <div class="info-card card-react" id="card-react-events"> <div class="card-body"> - <h5><i class="bi bi-mouse" aria-hidden="true"></i> Event Handling</h5> + <h5><i class="bi bi-cursor" aria-hidden="true"></i> Handling Events (React)</h5> <div class="card-content-wrapper"> - <p class="summary">Respond to user interactions (clicks, key presses, mouse moves) or browser events (load, resize). Use <span class="term">`addEventListener`</span>. Understand event object, bubbling/capturing. <a href="https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Building_blocks/Events" target="_blank">MDN Events</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseBrowserEvents" aria-expanded="false" aria-controls="collapseBrowserEvents"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Use camelCase event names (`onClick`, `onChange`). Pass event handler functions (often defined inline or as component methods). React uses a <span class="term">SyntheticEvent</span> system. <a href="https://react.dev/learn/responding-to-events" target="_blank">React Events</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactEvents" aria-expanded="false" aria-controls="collapseReactEvents"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseBrowserEvents"> - <h6>Attaching Listeners</h6> - <pre><code class="language-javascript">const button = document.getElementById('myButton'); + <div class="collapse collapse-content" id="collapseReactEvents"> + <h6>Syntax</h6> + <pre><code class="language-jsx">function MyButton() { + function handleClick(event) { + console.log('Button clicked!', event); // event is SyntheticEvent + // event.preventDefault(); // Can still prevent default + } -function handleClick(event) { - console.log('Button clicked!', event.target); - // event.preventDefault(); // Stop default action (e.g., form submission) - // event.stopPropagation(); // Stop event from bubbling up -} + function handleChange(event) { + console.log('Input value:', event.target.value); + } -button.addEventListener('click', handleClick); -// To remove: button.removeEventListener('click', handleClick); + return ( + <> + <button onClick={handleClick}>Click Me</button> + {/* Inline arrow function handler */} + <input onChange={(e) => console.log('Typed:', e.target.value)} /> + {/* Passing arguments */} + <button onClick={() => alert('Specific message!')}>Show Alert</button> + </> + ); +} </code></pre> - <h6>Event Object</h6> - <p>The callback function receives an `Event` object with details about the event (e.g., `event.target`, `event.type`, `event.clientX`, `event.key`).</p> - <h6>Event Phases</h6> + <h6>SyntheticEvent</h6> <ul> - <li><strong>Capturing Phase:</strong> Event travels down from window to target.</li> - <li><strong>Target Phase:</strong> Event reaches the target element.</li> - <li><strong>Bubbling Phase:</strong> Event travels up from target to window (default for most events).</li> + <li>React wraps the browser's native event in a `SyntheticEvent` object.</li> + <li>Provides a cross-browser consistent API (e.g., `event.preventDefault()`, `event.stopPropagation()`).</li> + <li>Access the native event via `event.nativeEvent`.</li> + <li>Event pooling (in older React versions, largely removed now) meant you couldn't access event properties asynchronously without `event.persist()`. This is less of a concern in modern React.</li> </ul> - <h6>Event Delegation</h6> - <p>Attach a single event listener to a parent element to manage events for multiple child elements, especially dynamically added ones. Check `event.target` within the handler.</p> - <!-- Detailed content needed: Event object, common events (click, mouseover, keydown, submit, load), bubbling/capturing, preventDefault, stopPropagation, event delegation --> - </div> - </div> - </div> - </div> <!-- /.row --> - </div> <!-- /.schema-container --> + <h6>Passing Handlers as Props</h6> + <p>Often, child components receive handlers from parents via props to communicate events upwards.</p> + <pre><code class="language-jsx">function ChildButton({ onCustomClick }) { // Receives handler via prop + return <button onClick={onCustomClick}>Click Child</button>; +} - <!-- IV. Frontend Frameworks & Libraries --> - <div class="schema-container section-frameworks" data-section-id="section-frameworks" data-section-name="Frameworks"> - <h2 class="section-title" id="section-frameworks-title">Frontend Frameworks & Libraries</h2> - <div class="row"> - <!-- React Cards --> - <div class="col-lg-4 col-md-6"> - <div class="info-card card-react" id="card-react-overview"> - <div class="card-body"> - <h5><i class="bi bi-gem" aria-hidden="true"></i> React Overview</h5> - <div class="card-content-wrapper"> - <p class="summary">Popular library for building user interfaces using a <span class="term" data-bs-toggle="tooltip" title="JS objects representing the desired UI state. React updates the actual DOM efficiently.">Virtual DOM</span> and a <span class="term" data-bs-toggle="tooltip" title="Building UIs from reusable pieces (components).">component-based</span> architecture. Focuses on declarative UI. <a href="https://react.dev/" target="_blank">React Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactOverview" aria-expanded="false" aria-controls="collapseReactOverview"> - Details <i class="bi bi-chevron-down"></i> - </button> - </div> - </div> - <div class="collapse collapse-content" id="collapseReactOverview"> - <h6>Key Concepts</h6> - <ul> - <li><strong>Components:</strong> Reusable UI pieces (typically functions returning JSX).</li> - <li><strong>JSX:</strong> Syntax extension allowing HTML-like code in JS.</li> - <li><strong>Props:</strong> Data passed down from parent to child components (read-only).</li> - <li><strong>State:</strong> Data managed *within* a component that can change over time.</li> - <li><strong>Hooks:</strong> Functions (like `useState`, `useEffect`) letting you "hook into" React state and lifecycle features from function components.</li> - <li><strong>Virtual DOM:</strong> In-memory representation used to optimize DOM updates ("diffing").</li> - <li><strong>Unidirectional Data Flow:</strong> Data flows down from parent to child components via props. State changes trigger re-renders.</li> - </ul> +function Parent() { + function handleChildClick() { + console.log('Child button was clicked!'); + } + return <ChildButton onCustomClick={handleChildClick} />; +} +</code></pre> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-react" id="card-react-hooks"> + <div class="info-card card-react" id="card-react-conditional"> <div class="card-body"> - <h5><i class="bi bi-life-preserver" aria-hidden="true"></i> State & Lifecycle (Hooks) <span class="version-tag">React 16.8+</span></h5> + <h5><i class="bi bi-toggles" aria-hidden="true"></i> Conditional Rendering</h5> <div class="card-content-wrapper"> - <p class="summary">Manage component state (`useState`) and side effects (`useEffect`) in functional components. Share state with `useContext`. <a href="https://react.dev/reference/react/hooks" target="_blank">React Hooks Reference</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactHooks" aria-expanded="false" aria-controls="collapseReactHooks"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Render different UI based on conditions. Use standard JS: `if`/`else`, ternary operator (`condition ? ... : ...`), logical AND (`&&`), or `null` return. <a href="https://react.dev/learn/conditional-rendering" target="_blank">React Conditional Rendering</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactConditional" aria-expanded="false" aria-controls="collapseReactConditional"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseReactHooks"> - <h6>Core Hooks</h6> - <ul> - <li><strong>`useState(initialState)`:</strong> Returns a stateful value and a function to update it. Re-renders component on update. - <pre><code class="language-javascript">const [count, setCount] = useState(0); -// ... -setCount(prevCount => prevCount + 1); // Functional update -// setCount(count + 1); // Direct update</code></pre> - </li> - <li><strong>`useEffect(setup, dependencies?)`:</strong> Performs side effects (data fetching, subscriptions, manual DOM changes). Runs after render. `dependencies` array controls re-run behavior. Empty array `[]` runs once on mount/unmount. No array runs after every render. - <pre><code class="language-javascript">// Fetch data on mount -useEffect(() => { - let isMounted = true; // Prevent state update on unmounted component - fetchData().then(data => { - if (isMounted) setData(data); - }); - return () => { isMounted = false; }; // Cleanup -}, []); // Runs only once after initial render - -// Run when 'userId' prop changes -useEffect(() => { - console.log('User ID changed:', userId); - // Cleanup function (optional) - return () => { - console.log('Cleaning up effect for old userId'); - }; -}, [userId]);</code></pre> - </li> - <li><strong>`useContext(Context)`:</strong> Subscribes to React context to read its value. Avoids prop drilling. - <pre><code class="language-javascript">// ThemeContext.js -// export const ThemeContext = React.createContext('light'); -const theme = useContext(ThemeContext); -// ... use theme value (e.g., <div className={`App ${theme}`}>)</code></pre> - </li> - </ul> - <h6>Other Common Hooks</h6> - <p>`useReducer` (complex state logic), `useCallback` (memoize callbacks), `useMemo` (memoize computed values), `useRef` (access DOM/persist mutable values), `useLayoutEffect` (synchronous DOM mutations).</p> + <div class="collapse collapse-content" id="collapseReactConditional"> + <h6>Common Patterns</h6> + <ul> + <li><strong>`if/else` (outside JSX):</strong> Prepare content in variables before returning JSX.</li> + <li><strong>Ternary Operator (`condition ? exprIfTrue : exprIfFalse`):</strong> Inline conditional expression.</li> + <li><strong>Logical AND (`condition && expression`):</strong> Renders `expression` only if `condition` is truthy. If `condition` is falsy, renders `false` (which React ignores).</li> + <li><strong>Returning `null`:</strong> A component returning `null` renders nothing.</li> + </ul> + <pre><code class="language-jsx">function LoginStatus({ isLoggedIn }) { + // 1. Using if/else + let message; + if (isLoggedIn) { + message = <p>Welcome back!</p>; + } else { + message = <p>Please log in.</p>; + } + + return ( + <div> + {message} + + {/* 2. Using Ternary Operator */} + <button>{isLoggedIn ? 'Log Out' : 'Log In'}</button> + + {/* 3. Using Logical AND (only render if logged in) */} + {isLoggedIn && <UserProfile />} + + {/* 4. Returning null (example inside another component) */} + {/* {showPopup ? <Popup /> : null} */} + </div> + ); +} + +function UserProfile(){ return <span>User Profile</span>; } +</code></pre> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-react" id="card-react-jsx"> + <div class="info-card card-react" id="card-react-lists"> <div class="card-body"> - <h5><i class="bi bi-filetype-jsx" aria-hidden="true"></i> JSX</h5> + <h5><i class="bi bi-list-task" aria-hidden="true"></i> Lists & Keys</h5> <div class="card-content-wrapper"> - <p class="summary"><span class="term">JavaScript XML</span>: Syntax extension allowing HTML-like syntax within JavaScript. Transpiled to `React.createElement()` calls. <a href="https://react.dev/learn/writing-markup-with-jsx" target="_blank">React JSX Intro</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactJsx" aria-expanded="false" aria-controls="collapseReactJsx"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Render collections of items using array methods like `.map()`. Each list item needs a unique, stable <span class="term">`key`</span> prop for efficient updates. <a href="https://react.dev/learn/rendering-lists" target="_blank">React Rendering Lists</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseReactLists" aria-expanded="false" aria-controls="collapseReactLists"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseReactJsx"> - <h6>Key Features</h6> - <ul> - <li><strong>Expressions:</strong> Embed JS expressions using curly braces `{}`. E.g., `<h1>Hello, {user.name}</h1>`.</li> - <li><strong>Attributes:</strong> Use camelCase for HTML attributes (e.g., `className` for `class`, `htmlFor` for `for`). Boolean attributes can be written shorthand (e.g., `disabled` is same as `disabled={true}`).</li> - <li><strong>Styling:</strong> Pass a style object to the `style` attribute: `style={{ color: 'blue', fontSize: '16px' }}`.</li> - <li><strong>Fragments:</strong> Use `<>` or `<React.Fragment>` to return multiple elements without a wrapper div.</li> - <li><strong>Comments:</strong> Use JS comments within braces: `{/* This is a comment */}`.</li> - <li><strong>Self-closing tags:</strong> Required for elements without children, e.g. `<img src="..." />`.</li> - </ul> - <pre><code class="language-jsx">function Greeting({ name, items }) { - const isLoggedIn = true; - const listItems = items.map(item => <li key={item.id}>{item.text}</li>); + <div class="collapse collapse-content" id="collapseReactLists"> + <h6>Rendering with `.map()`</h6> + <pre><code class="language-jsx">function TodoList({ todos }) { + // todos is an array like [{ id: 1, text: 'Learn React' }, { id: 2, text: 'Build App' }] + + const listItems = todos.map(todo => + // Key must be unique among siblings! + <li key={todo.id}> + {todo.text} + </li> + ); + return <ul>{listItems}</ul>; +} +</code></pre> + <h6>The `key` Prop</h6> + <ul> + <li>Helps React identify which items have changed, are added, or are removed.</li> + <li>Keys should be **unique** among siblings in the list.</li> + <li>Keys should be **stable** (not change between renders for the same item).</li> + <li>Usually use item IDs from your data (`item.id`).</li> + <li>**Avoid using array index as key** if the list can be reordered, filtered, or items added/removed in the middle, as this can lead to bugs and performance issues. Use index only if list is static and has no IDs.</li> + </ul> + <h6>Extracting List Item Components</h6> + <p>For more complex list items, extract them into their own component. The `key` still needs to be on the element returned by `.map`.</p> + <pre><code class="language-jsx">function TodoItem({ todo }) { // Receives single todo item + return <li>{todo.text}</li>; +} + +function TodoList({ todos }) { return ( - <> {/* React Fragment */} - <h1 className="title" style={{ color: 'purple', fontWeight: 'bold' }}> - Hello, {name}! - </h1> - {isLoggedIn && <p>Welcome back!</p>} {/* Conditional rendering */} - {items.length > 0 ? ( - <ul>{listItems}</ul> - ) : ( - <p>No items to display.</p> + <ul> + {todos.map(todo => + // Key goes here on the component instance + <TodoItem key={todo.id} todo={todo} /> )} - <input type="text" placeholder="Enter something" disabled /> - </> + </ul> ); } </code></pre> </div> </div> </div> + <!-- Other Framework Cards --> <div class="col-lg-4 col-md-6"> - <div class="info-card card-vue" id="card-vue-overview"> + <div class="info-card card-vue" id="card-vue-overview"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-triangle" aria-hidden="true"></i> Vue.js Overview</h5> <div class="card-content-wrapper"> - <p class="summary">Progressive framework for building UIs. Known for its approachability, template syntax, and reactivity system. Offers Options API and Composition API. <a href="https://vuejs.org/" target="_blank">Vue Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseVueOverview" aria-expanded="false" aria-controls="collapseVueOverview"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Progressive framework focused on approachability. Uses HTML-based templates, reactive data, and component composition. Supports Options & Composition API. <a href="https://vuejs.org/" target="_blank">Vue Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseVueOverview" aria-expanded="false" aria-controls="collapseVueOverview"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseVueOverview"> <h6>Key Concepts</h6> <ul> - <li><strong>Declarative Rendering:</strong> HTML-based template syntax.</li> - <li><strong>Reactivity:</strong> Data changes automatically update the DOM.</li> - <li><strong>Components:</strong> Single File Components (`.vue` files) with template, script, and style sections.</li> - <li><strong>Options API:</strong> Organizes component logic using options like `data`, `methods`, `computed`, `watch`, lifecycle hooks.</li> - <li><strong>Composition API (Vue 3+):</strong> More flexible way to organize logic using functions like `ref`, `reactive`, `computed`, `watch`, `onMounted`.</li> - <li><strong>Directives:</strong> Special attributes with `v-` prefix (e.g., `v-if`, `v-for`, `v-bind`, `v-on`).</li> + <li><strong>Templates:</strong> HTML-based syntax binding DOM to component data using directives (`v-bind`, `v-on`, `v-model`, `v-if`, `v-for`).</li> + <li><strong>Reactivity:</strong> Core system automatically tracks dependencies and updates DOM when state changes.</li> + <li><strong>Components:</strong> Often Single File Components (`.vue`) encapsulating template, script (`<script setup>` for Composition API), and style.</li> + <li><strong>Options API:</strong> Traditional way using `data()`, `methods`, `computed`, `watch`, lifecycle hooks options.</li> + <li><strong>Composition API (Vue 3+):</strong> Organize logic by feature using functions like `ref()`, `reactive()`, `computed()`, `watch()`, `onMounted()`. More flexible for large components and logic reuse.</li> </ul> - <p><em>More detail on template syntax, Options vs Composition API needed.</em></p> + <p><em>More detail on template syntax, directives, and API differences needed.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-angular" id="card-angular-overview"> + <div class="info-card card-angular" id="card-angular-overview"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-shield-shaded" aria-hidden="true"></i> Angular Overview</h5> <div class="card-content-wrapper"> - <p class="summary">A comprehensive platform and framework for building complex client applications in HTML and TypeScript. Opinionated structure with powerful features. <a href="https://angular.io/" target="_blank">Angular Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAngularOverview" aria-expanded="false" aria-controls="collapseAngularOverview"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Comprehensive platform for building large-scale apps using TypeScript. Features components, modules, DI, routing, RxJS integration, CLI tooling. Opinionated. <a href="https://angular.io/" target="_blank">Angular Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAngularOverview" aria-expanded="false" aria-controls="collapseAngularOverview"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseAngularOverview"> <h6>Key Concepts</h6> <ul> - <li><strong>TypeScript-based:</strong> Strong typing is a core feature.</li> - <li><strong>Components & Templates:</strong> Building blocks of UI, with HTML templates and component logic.</li> - <li><strong>Modules (NgModules):</strong> Organize components, directives, pipes, and services.</li> - <li><strong>Dependency Injection (DI):</strong> Built-in system for managing dependencies.</li> - <li><strong>Services:</strong> Reusable logic, often for data fetching or business rules.</li> - <li><strong>Routing:</strong> Powerful client-side navigation.</li> - <li><strong>RxJS:</strong> Heavily used for asynchronous operations and event handling (Observables).</li> - <li><strong>Angular CLI:</strong> Essential for project creation, generation, building, and testing.</li> + <li><strong>TypeScript:</strong> Core language, enabling strong typing and OOP features.</li> + <li><strong>Components:</strong> Combine HTML template, CSS styles, and TypeScript class logic (`@Component` decorator).</li> + <li><strong>Templates:</strong> Enhanced HTML with data binding (`[]`, `()`, `[()]`) and directives (`*ngIf`, `*ngFor`).</li> + <li><strong>Modules (NgModules):</strong> Organize application parts, declare components/directives/pipes, manage dependencies (`@NgModule` decorator). Standalone Components becoming more common.</li> + <li><strong>Dependency Injection (DI):</strong> Built-in hierarchical injector provides services and dependencies.</li> + <li><strong>Services:</strong> Classes (`@Injectable`) for reusable logic, data access.</li> + <li><strong>Routing:</strong> Powerful module (`RouterModule`) for client-side navigation.</li> + <li><strong>RxJS:</strong> Extensively used for handling asynchronous events and data streams (Observables).</li> + <li><strong>Angular CLI:</strong> Essential tool for project scaffolding, generation, building, testing, deployment.</li> </ul> - <p><em>More detail on data binding, directives, pipes, and forms needed.</em></p> + <p><em>More detail on decorators, data binding syntax, directives, pipes, and RxJS needed.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-svelte" id="card-svelte-overview"> + <div class="info-card card-svelte" id="card-svelte-overview"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-fire" aria-hidden="true"></i> Svelte Overview</h5> <div class="card-content-wrapper"> - <p class="summary">A radical new approach to building UIs. Svelte compiles your components into highly efficient imperative code that surgically updates the DOM. <a href="https://svelte.dev/" target="_blank">Svelte Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSvelteOverview" aria-expanded="false" aria-controls="collapseSvelteOverview"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">A compiler that turns declarative component code into efficient imperative JavaScript. No Virtual DOM. Truly reactive via assignments. Minimal runtime. <a href="https://svelte.dev/" target="_blank">Svelte Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseSvelteOverview" aria-expanded="false" aria-controls="collapseSvelteOverview"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseSvelteOverview"> <h6>Key Concepts</h6> <ul> - <li><strong>Compiler, not a Runtime Library:</strong> Shifts work from the browser to the build step.</li> - <li><strong>No Virtual DOM:</strong> Generates code that updates the DOM directly.</li> - <li><strong>Reactive by Default:</strong> Assignments to variables trigger updates (`let count = 0; count++;`).</li> - <li><strong>Single File Components (`.svelte`):</strong> Combine script, template, and style in one file.</li> - <li><strong>Stores:</strong> Built-in mechanism for managing state outside components (readable, writable, derived).</li> - <li><strong>Transitions & Animations:</strong> First-class support for UI animations.</li> + <li><strong>Compiler Approach:</strong> Shifts work to build time, resulting in smaller bundles and faster runtime performance.</li> + <li><strong>No Virtual DOM:</strong> Generates highly optimized imperative code to update the DOM directly when state changes.</li> + <li><strong>Reactivity:</strong> Variable assignments (`count = 1`, `user.name = 'X'`) automatically trigger updates where those variables are used. Use `$: ` for reactive declarations/statements.</li> + <li><strong>Single File Components (`.svelte`):</strong> Combine `<script>`, template (HTML-like), and `<style>` (scoped by default).</li> + <li><strong>Stores:</strong> Built-in system (`writable`, `readable`, `derived`) for managing state outside components and sharing it reactively.</li> + <li><strong>Transitions & Animations:</strong> First-class directives (`transition:`, `animate:`, `in:`, `out:`) for smooth UI effects.</li> + <li><strong>Context API:</strong> Similar to React/Vue for avoiding prop drilling (`setContext`, `getContext`).</li> </ul> - <p><em>More detail on template syntax, reactive declarations (`$: `), stores, and event handling needed.</em></p> + <p><em>More detail on template syntax (logic blocks, event handling), reactive declarations, stores needed.</em></p> </div> </div> </div> @@ -1233,152 +1906,322 @@ const theme = useContext(ThemeContext); <h2 class="section-title" id="section-state-title">State Management Patterns & Libraries</h2> <div class="row"> <div class="col-lg-4 col-md-6"> - <div class="info-card card-state" id="card-state-concepts"> + <div class="info-card card-state" id="card-state-concepts"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-diagram-3-fill" aria-hidden="true"></i> State Management Concepts</h5> <div class="card-content-wrapper"> - <p class="summary">Strategies for handling data that changes over time in applications. Distinguish <span class="term">local state</span> (within a component) from <span class="term">global state</span> (shared across components). Avoid <span class="term" data-bs-toggle="tooltip" title="Passing props through many intermediate components.">prop drilling</span>. <a href="https://react.dev/learn/sharing-state-between-components" target="_blank">React State Sharing</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateConcepts" aria-expanded="false" aria-controls="collapseStateConcepts"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Handling data that changes over time. Distinguish <span class="term">local</span> (component) vs <span class="term">global</span> (shared) state. Solutions aim to manage complexity, avoid <span class="term">prop drilling</span>, improve predictability. <a href="https://react.dev/learn/sharing-state-between-components" target="_blank">React State Sharing</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateConcepts" aria-expanded="false" aria-controls="collapseStateConcepts"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseStateConcepts"> <h6>Types of State</h6> <ul> - <li><strong>Local State:</strong> Managed within a single component (e.g., form input values, UI toggles). Often handled by component's internal state mechanism (e.g., `useState` in React).</li> - <li><strong>Global State:</strong> Shared across multiple components, often unrelated in the component tree (e.g., user authentication status, theme).</li> + <li><strong>Local/Component State:</strong> Managed within a component (e.g., form input, toggle status). Use framework's built-in state (React `useState`, Vue `ref`, Angular component properties).</li> + <li><strong>Cross-Component State:</strong> State shared between few related components. Often handled by "lifting state up" to a common ancestor.</li> + <li><strong>App-Wide/Global State:</strong> Shared across many components, potentially unrelated (e.g., user auth, theme, shopping cart). Requires dedicated solutions.</li> </ul> - <h6>Challenges</h6> + <h6>Challenges Without Libraries</h6> <ul> - <li><strong>Prop Drilling:</strong> Passing data through many layers of intermediate components that don't directly use the data.</li> - <li><strong>Complexity:</strong> Managing how and when state updates occur, especially in larger applications.</li> - <li><strong>Debugging:</strong> Tracing state changes and identifying sources of bugs.</li> + <li><strong>Prop Drilling:</strong> Passing state down through multiple layers of intermediate components that don't need it. Cumbersome and hard to refactor.</li> + <li><strong>Complexity:</strong> Tracking where state lives and how it changes becomes difficult in large apps.</li> + <li><strong>Debugging:</strong> Hard to trace state updates and find the source of bugs.</li> </ul> - <p><em>Choosing the right state management approach depends on application size and complexity.</em></p> + <p><em>Dedicated libraries (Context, Redux, Zustand, Pinia, etc.) provide patterns and tools to address these challenges.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-state card-react" id="card-state-context"> <!-- Specific react color --> + <div class="info-card card-state card-react" id="card-state-context"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-share" aria-hidden="true"></i> React Context API <span class="version-tag">React 16.3+</span></h5> <div class="card-content-wrapper"> - <p class="summary">Built-in React mechanism to share state down the component tree without prop drilling. Use `createContext`, `Provider`, and `useContext`. <a href="https://react.dev/learn/passing-data-deeply-with-context" target="_blank">React Context Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateContext" aria-expanded="false" aria-controls="collapseStateContext"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Built-in way to pass data through component tree without prop drilling. Use `createContext`, `<Provider>`, `useContext`. Best for low-frequency updates. <a href="https://react.dev/learn/passing-data-deeply-with-context" target="_blank">React Context Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateContext" aria-expanded="false" aria-controls="collapseStateContext"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseStateContext"> - <h6>Usage</h6> - <pre><code class="language-javascript">// 1. Create Context -// MyContext.js -import React from 'react'; -export const MyContext = React.createContext(null); // Default value - -// 2. Provide Context Value -// App.js -import { MyContext } from './MyContext'; -function App() { - const sharedValue = "Hello from Context!"; + <h6>Core API</h6> + <ul> + <li><strong>`React.createContext(defaultValue)`:</strong> Creates a Context object. `defaultValue` is used only when a component has no matching Provider above it.</li> + <li><strong>`<MyContext.Provider value={/* some value */}>`</strong>: Component that makes the context `value` available to all consuming components deep in its subtree.</li> + <li><strong>`useContext(MyContext)`:</strong> Hook used in functional components to read the current context value from the nearest matching Provider. Causes re-render when Provider's `value` changes.</li> + <li><strong>`<MyContext.Consumer>` (Legacy):</strong> Render prop component for consuming context in class components or where Hooks aren't usable.</li> + </ul> + <pre><code class="language-jsx">// ThemeContext.js +import React, { useState, useContext } from 'react'; + +const ThemeContext = React.createContext('light'); // Default value +const ThemeUpdateContext = React.createContext(() => {}); // For update function + +export function useTheme() { return useContext(ThemeContext); } +export function useThemeUpdate() { return useContext(ThemeUpdateContext); } + +export function ThemeProvider({ children }) { + const [theme, setTheme] = useState('light'); + function toggleTheme() { + setTheme(prevTheme => prevTheme === 'light' ? 'dark' : 'light'); + } return ( - <MyContext.Provider value={sharedValue}> - <MyComponent /> - </MyContext.Provider> + <ThemeContext.Provider value={theme}> + <ThemeUpdateContext.Provider value={toggleTheme}> + {children} + </ThemeUpdateContext.Provider> + </ThemeContext.Provider> ); } -// 3. Consume Context Value // MyComponent.js -import React, { useContext } from 'react'; -import { MyContext } from './MyContext'; +import { useTheme, useThemeUpdate } from './ThemeContext'; + function MyComponent() { - const value = useContext(MyContext); - return <div>Shared Value: {value}</div>; + const theme = useTheme(); + const toggleTheme = useThemeUpdate(); + return ( + <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff' }}> + Current theme: {theme} + <button onClick={toggleTheme}>Toggle Theme</button> + </div> + ); } </code></pre> <h6>Considerations</h6> <ul> - <li>Good for low-frequency updates or relatively static data (e.g., theme, user info).</li> - <li>Can cause performance issues if the context value updates frequently and many components consume it, as all consumers re-render.</li> - <li>Often combined with `useReducer` for more complex state management within a context.</li> + <li>Simpler than Redux for many use cases.</li> + <li>Performance: Any component consuming the context via `useContext` will re-render whenever the Provider's `value` prop changes, even if the component only uses part of the value. Split contexts or use memoization (`useMemo`) for complex values to mitigate.</li> + <li>Often combined with `useState` or `useReducer` within the Provider component to manage the context state itself.</li> </ul> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-state" id="card-state-redux"> + <div class="info-card card-state" id="card-state-redux"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-arrow-repeat" aria-hidden="true"></i> Redux / RTK</h5> <div class="card-content-wrapper"> - <p class="summary">Predictable state container for JS apps. Centralized store, immutable updates via <span class="term">reducers</span> triggered by <span class="term">actions</span>. <span class="term">Redux Toolkit (RTK)</span> is the modern standard. <a href="https://redux-toolkit.js.org/" target="_blank">Redux Toolkit Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateRedux" aria-expanded="false" aria-controls="collapseStateRedux"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Predictable global state container. Central <span class="term">store</span>, immutable updates via pure <span class="term">reducers</span> triggered by dispatched <span class="term">actions</span>. <span class="term">Redux Toolkit (RTK)</span> simplifies setup. <a href="https://redux-toolkit.js.org/" target="_blank">Redux Toolkit Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateRedux" aria-expanded="false" aria-controls="collapseStateRedux"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseStateRedux"> - <h6>Core Principles (Classic Redux)</h6> - <ul> - <li><strong>Single Source of Truth:</strong> State of the whole application is stored in one object tree (the store).</li> - <li><strong>State is Read-Only:</strong> The only way to change state is by emitting an action (an object describing what happened).</li> - <li><strong>Changes are made with Pure Functions:</strong> Reducers (pure functions) specify how state changes in response to actions.</li> - </ul> - <h6>Redux Toolkit (RTK)</h6> - <p>Simplifies Redux development by providing:</p> + <h6>Core Concepts</h6> <ul> - <li><strong>`configureStore()`:</strong> Sets up a well-configured store with good defaults (e.g., Redux DevTools).</li> - <li><strong>`createSlice()`:</strong> Generates action creators and action types automatically, and allows writing "mutating" reducer logic with Immer.</li> - <li><strong>`createAsyncThunk()`:</strong> For handling asynchronous actions (e.g., API calls).</li> + <li><strong>Store:</strong> Single object holding the application state. Created with `configureStore` (RTK).</li> + <li><strong>Actions:</strong> Plain objects describing *what happened*. Have a `type` property (string) and often a `payload`. Action creators generate these objects.</li> + <li><strong>Reducers:</strong> Pure functions `(previousState, action) => newState`. Specify how state changes in response to actions. Must be immutable (return new state objects/arrays).</li> + <li><strong>Dispatch:</strong> Function (`store.dispatch(action)`) to send actions to the store, triggering reducers.</li> + <li><strong>Selectors:</strong> Functions to extract specific pieces of data from the store state. Often memoized (e.g., with Reselect) for performance.</li> + <li><strong>Middleware:</strong> Enhance `dispatch` to handle side effects (like API calls with `createAsyncThunk`), logging, etc.</li> </ul> - <p><em>Example of `createSlice` needed.</em></p> + <h6>Redux Toolkit (RTK) Simplifications</h6> + <pre><code class="language-javascript">// counterSlice.js +import { createSlice } from '@reduxjs/toolkit'; + +const counterSlice = createSlice({ + name: 'counter', + initialState: { value: 0 }, + reducers: { + // Action creators generated automatically (counterSlice.actions.increment) + increment(state) { + state.value += 1; // Can "mutate" state directly due to Immer integration + }, + decrement(state) { + state.value -= 1; + }, + incrementByAmount(state, action) { // Action has payload property + state.value += action.payload; + }, + }, +}); + +export const { increment, decrement, incrementByAmount } = counterSlice.actions; +export default counterSlice.reducer; + +// store.js +import { configureStore } from '@reduxjs/toolkit'; +import counterReducer from './counterSlice'; + +export const store = configureStore({ + reducer: { + counter: counterReducer, + // other reducers... + }, +}); + +// MyReactComponent.jsx +import { useSelector, useDispatch } from 'react-redux'; +import { increment, decrement } from './counterSlice'; + +function CounterComponent() { + // Select data from store + const count = useSelector((state) => state.counter.value); + // Get dispatch function + const dispatch = useDispatch(); + + return ( + <div> + Count: {count} + <button onClick={() => dispatch(increment())}>+</button> + <button onClick={() => dispatch(decrement())}>-</button> + </div> + ); +} +</code></pre> + <p><em>RTK significantly reduces boilerplate compared to classic Redux. Consider RTK Query for data fetching/caching.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-state card-react" id="card-state-zustand"> + <div class="info-card card-state card-react" id="card-state-zustand"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-lightbulb" aria-hidden="true"></i> Zustand</h5> <div class="card-content-wrapper"> - <p class="summary">A small, fast, and scalable bearbones state-management solution for React using simplified flux principles. Hook-based API. <a href="https://github.com/pmndrs/zustand" target="_blank">Zustand GitHub</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateZustand" aria-expanded="false" aria-controls="collapseStateZustand"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Minimalist hook-based state management for React. Unopinionated, fast, less boilerplate than Redux. Uses `create` to build a store hook. <a href="https://github.com/pmndrs/zustand" target="_blank">Zustand GitHub</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateZustand" aria-expanded="false" aria-controls="collapseStateZustand"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseStateZustand"> - <h6>Key Features</h6> - <ul> - <li><strong>Minimalistic:</strong> Very little boilerplate.</li> - <li><strong>Hook-based:</strong> Create a store, bind it to components using a custom hook.</li> - <li><strong>Unopinionated:</strong> Flexible, can be used for simple or complex state.</li> - <li><strong>Middleware Support:</strong> For devtools, persistence, etc.</li> - </ul> + <h6>Core Concept</h6> + <p>Define a store using `create` which takes a function `(set, get) => ({...})`. `set` updates state, `get` accesses current state. The `create` function returns a custom hook to use in components.</p> <pre><code class="language-javascript">// store.js import { create } from 'zustand'; -const useStore = create((set) => ({ +const useBearStore = create((set) => ({ bears: 0, - increasePopulation: () => set((state) => ({ bears: state.bears + 1 })), - removeAllBears: () => set({ bears: 0 }), + increase: () => set((state) => ({ bears: state.bears + 1 })), + decrease: () => set((state) => ({ bears: Math.max(0, state.bears - 1) })), + reset: () => set({ bears: 0 }), + // Example with async action (no extra middleware needed usually) + fetchBears: async () => { + // set({ loading: true }); // Optional loading state + try { + const response = await fetch('/api/bears'); + const numBears = await response.json(); + set({ bears: numBears /*, loading: false */ }); + } catch (error) { + // set({ error: error.message, loading: false }); + console.error("Failed to fetch bears", error); + } + } })); -export default useStore; +export default useBearStore; -// MyComponent.js -import useStore from './store'; +// MyComponent.jsx +import useBearStore from './store'; +import React, { useEffect } from 'react'; function BearCounter() { - const bears = useStore((state) => state.bears); - return <h1>{bears} around here ...</h1>; + // Select specific state slice - component only re-renders if this slice changes + const bears = useBearStore((state) => state.bears); + return <h1>{bears} bears around here</h1>; } function Controls() { - const increasePopulation = useStore((state) => state.increasePopulation); - return <button onClick={increasePopulation}>one up</button>; + // Select actions + const increase = useBearStore((state) => state.increase); + const reset = useBearStore((state) => state.reset); + const fetchBears = useBearStore((state) => state.fetchBears); + + useEffect(() => { + fetchBears(); // Fetch on mount example + }, [fetchBears]); // Dependency array includes the action + + return ( + <> + <button onClick={increase}>Add Bear</button> + <button onClick={reset}>Reset Bears</button> + </> + ); } </code></pre> + <h6>Advantages</h6> + <ul> + <li>Simple API, minimal boilerplate.</li> + <li>Renders components only when the selected state slice changes.</li> + <li>Can be used outside React components.</li> + <li>Middleware support (devtools, persist, immer, etc.).</li> + </ul> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-state card-vue" id="card-state-pinia"> + <div class="card-body"> + <h5><i class="bi bi-pin-map" aria-hidden="true"></i> Pinia (Vue)</h5> + <div class="card-content-wrapper"> + <p class="summary">Official state management library for Vue 3. Intuitive, type-safe, modular store definition. Supports Options & Composition API styles. <a href="https://pinia.vuejs.org/" target="_blank">Pinia Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStatePinia" aria-expanded="false" aria-controls="collapseStatePinia"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseStatePinia"> + <h6>Core Concepts</h6> + <ul> + <li><strong>Stores:</strong> Defined using `defineStore`. Each store has a unique ID.</li> + <li><strong>State:</strong> Defined as a function returning the initial state object.</li> + <li><strong>Getters:</strong> Computed properties based on store state (`computed()` under the hood).</li> + <li><strong>Actions:</strong> Methods that can contain async operations and modify state.</li> + </ul> + <pre><code class="language-javascript">// stores/counter.js +import { defineStore } from 'pinia'; + +export const useCounterStore = defineStore('counter', { + state: () => ({ count: 0, name: 'My Counter' }), + getters: { + doubleCount: (state) => state.count * 2, + }, + actions: { + increment() { + this.count++; // Can directly mutate state here + }, + async incrementAsync() { + // await someApiCall(); + this.increment(); + } + }, +}); + +// MyComponent.vue +// <script setup> +import { useCounterStore } from '@/stores/counter'; +import { storeToRefs } from 'pinia'; // Needed for reactive destructuring + +const counterStore = useCounterStore(); +// Destructure state/getters with reactivity using storeToRefs +const { count, doubleCount, name } = storeToRefs(counterStore); +// Actions can be destructured directly +const { increment } = counterStore; +// </script> + +// <template> +// <p>{{ name }}: {{ count }} (Double: {{ doubleCount }})</p> +// <button @click="increment">Increment</button> +// </template> +</code></pre> + <p><em>Considered the successor to Vuex for Vue 3.</em></p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-state card-angular" id="card-state-ngrx"> + <div class="card-body"> + <h5><i class="bi bi-recycle" aria-hidden="true"></i> NgRx (Angular)</h5> + <div class="card-content-wrapper"> + <p class="summary">Reactive state management for Angular inspired by Redux, using RxJS. Provides Store, Actions, Reducers, Effects (for side effects), Selectors. Opinionated. <a href="https://ngrx.io/" target="_blank">NgRx Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseStateNgrx" aria-expanded="false" aria-controls="collapseStateNgrx"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseStateNgrx"> + <h6>Core Concepts</h6> + <ul> + <li><strong>Store:</strong> Centralized state container, an RxJS Observable stream.</li> + <li><strong>Actions:</strong> Unique events describing state changes (`createAction`).</li> + <li><strong>Reducers:</strong> Pure functions defining state transitions based on actions (`createReducer`, `on`).</li> + <li><strong>Selectors:</strong> Pure functions to derive slices of state from the store (`createSelector`). Memoized for performance.</li> + <li><strong>Effects:</strong> Handle side effects (like API calls) triggered by actions, often dispatching new actions upon completion (`createEffect`, uses RxJS operators).</li> + </ul> + <p>NgRx follows Redux principles closely but leverages RxJS Observables heavily for managing state streams and asynchronous operations within Effects. It involves more boilerplate compared to some other solutions but offers powerful, predictable state management for large Angular applications.</p> + <p><em>Code examples for Actions, Reducers, Effects, Selectors, and component usage needed.</em></p> </div> </div> </div> @@ -1390,172 +2233,258 @@ function Controls() { <h2 class="section-title" id="section-tooling-title">Ecosystem & Tooling</h2> <div class="row"> <div class="col-lg-4 col-md-6"> - <div class="info-card card-tooling" id="card-tooling-npm"> + <div class="info-card card-tooling" id="card-tooling-npm"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-box" aria-hidden="true"></i> Package Managers</h5> <div class="card-content-wrapper"> - <p class="summary"><span class="term">npm</span>, <span class="term">yarn</span>, <span class="term">pnpm</span> manage project dependencies listed in `package.json`. Install, update, and remove external libraries (packages). <a href="https://docs.npmjs.com/" target="_blank">npm Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingNpm" aria-expanded="false" aria-controls="collapseToolingNpm"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary"><span class="term">npm</span>, <span class="term">yarn</span>, <span class="term">pnpm</span> manage project dependencies (`node_modules`) via `package.json`. Install, update, remove packages. Run scripts. <a href="https://docs.npmjs.com/" target="_blank">npm Docs</a> | <a href="https://yarnpkg.com/" target="_blank">Yarn</a> | <a href="https://pnpm.io/" target="_blank">pnpm</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingNpm" aria-expanded="false" aria-controls="collapseToolingNpm"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseToolingNpm"> - <h6>`package.json`</h6> + <h6>`package.json` Key Fields</h6> <ul> - <li><strong>`dependencies`</strong>: Packages required for production.</li> - <li><strong>`devDependencies`</strong>: Packages for development (e.g., linters, testing tools).</li> - <li><strong>`scripts`</strong>: Custom commands (e.g., `npm start`, `npm run build`).</li> + <li><strong>`name`</strong>, <strong>`version`</strong>: Package identification.</li> + <li><strong>`dependencies`</strong>: Packages needed for the application to run.</li> + <li><strong>`devDependencies`</strong>: Packages needed only for development (testing, building, linting).</li> + <li><strong>`scripts`</strong>: Aliases for common command-line tasks (e.g., `start`, `build`, `test`, `lint`). Run via `npm run <script-name>`.</li> + <li><strong>`main`</strong> / <strong>`module`</strong> / <strong>`exports`</strong>: Entry points for the package.</li> + <li><strong>`type`</strong>: `"module"` enables native ES Modules syntax in Node.js. Default is `"commonjs"`.</li> </ul> - <h6>Common Commands</h6> + <h6>Common Commands (npm example)</h6> <ul> - <li>`npm install <package>` or `yarn add <package>`</li> - <li>`npm install` or `yarn install` (or just `yarn`)</li> - <li>`npm uninstall <package>` or `yarn remove <package>`</li> - <li>`npm update <package>` or `yarn upgrade <package>`</li> - <li>`npx <command>` (Execute package binaries)</li> + <li>`npm install <package-name>`: Install package as dependency. Add `-D` or `--save-dev` for dev dependency.</li> + <li>`npm install`: Install all dependencies from `package.json` and `package-lock.json`.</li> + <li>`npm uninstall <package-name>`: Remove package.</li> + <li>`npm update`: Update packages based on `package.json` version ranges.</li> + <li>`npm outdated`: Check for outdated packages.</li> + <li>`npm run <script-name>`: Execute script defined in `scripts`.</li> + <li>`npx <package-name>`: Execute package binary without installing globally (e.g., `npx create-react-app my-app`).</li> </ul> - <p><em>Consider `package-lock.json` or `yarn.lock` for deterministic installs.</em></p> + <h6>Lock Files (`package-lock.json`, `yarn.lock`)</h6> + <p>Record exact versions of installed dependencies to ensure consistent installs across different environments/developers. Commit these files to source control.</p> + <h6>pnpm</h6> + <p>Alternative package manager focusing on disk space efficiency (shared store) and speed.</p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-tooling" id="card-tooling-bundlers"> + <div class="info-card card-tooling" id="card-tooling-bundlers"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-boxes" aria-hidden="true"></i> Module Bundlers</h5> <div class="card-content-wrapper"> - <p class="summary"><span class="term">Vite</span>, <span class="term">Webpack</span>, <span class="term">Parcel</span> process JS modules, assets (CSS, images) and bundle them for browser use. Handle transformations, optimization, dev server. <a href="https://vitejs.dev/" target="_blank">Vite</a> | <a href="https://webpack.js.org/" target="_blank">Webpack</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingBundlers" aria-expanded="false" aria-controls="collapseToolingBundlers"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary"><span class="term">Vite</span>, <span class="term">Webpack</span>, <span class="term">Parcel</span> process modules/assets, bundle for browser, optimize, provide dev server (HMR). Essential for modern frontend dev. <a href="https://vitejs.dev/" target="_blank">Vite</a> | <a href="https://webpack.js.org/" target="_blank">Webpack</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingBundlers" aria-expanded="false" aria-controls="collapseToolingBundlers"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseToolingBundlers"> - <h6>Key Functions</h6> + <h6>Why Bundle?</h6> + <ul> + <li>Browsers historically didn't support modules efficiently (or at all).</li> + <li>Allows using non-JS assets (CSS, images, fonts) in JS modules.</li> + <li>Enables transformations (TypeScript, Babel, Sass/PostCSS).</li> + <li>Optimizations: Minification, tree-shaking, code splitting.</li> + </ul> + <h6>Key Tools</h6> <ul> - <li><strong>Dependency Graph:</strong> Traverses `import` statements to build a graph of all modules.</li> - <li><strong>Transformations:</strong> Via plugins/loaders (e.g., Babel for JS, PostCSS for CSS, TypeScript compilation).</li> - <li><strong>Optimization:</strong> Minification, tree-shaking (removing unused code), code splitting.</li> - <li><strong>Development Server:</strong> Provides local server with Hot Module Replacement (HMR) for faster development.</li> + <li><strong>Webpack:</strong> Mature, highly configurable, vast plugin ecosystem. Can be complex. Uses loaders for transformations, plugins for broader tasks.</li> + <li><strong>Vite:</strong> Modern, extremely fast dev server leveraging native ES Modules. Uses Rollup for production builds. Simpler configuration, opinionated defaults. Excellent DX.</li> + <li><strong>Parcel:</strong> Zero-configuration bundler. Aims for ease of use.</li> + <li><strong>Rollup:</strong> Primarily focused on bundling libraries (ESM output), often used under the hood by others (like Vite).</li> </ul> - <h6>Vite vs. Webpack</h6> + <h6>Common Features</h6> <ul> - <li><strong>Vite:</strong> Extremely fast dev server (uses native ES modules). Simpler configuration. Good for modern projects.</li> - <li><strong>Webpack:</strong> Highly configurable and mature. Extensive plugin ecosystem. Can be complex to set up.</li> + <li><strong>Development Server:</strong> Local server for development.</li> + <li><strong>Hot Module Replacement (HMR):</strong> Update modules in the browser without full page reload during development.</li> + <li><strong>Code Splitting:</strong> Break bundle into smaller chunks loaded on demand.</li> + <li><strong>Tree Shaking:</strong> Eliminate unused code from final bundle.</li> + <li><strong>Asset Handling:</strong> Importing CSS, images, fonts, etc.</li> + <li><strong>Environment Variables:</strong> Injecting build-time variables (`process.env` or `import.meta.env`).</li> </ul> - <p><em>Configuration examples for Vite and Webpack would be useful here.</em></p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-tooling" id="card-tooling-ts"> + <div class="info-card card-tooling" id="card-tooling-transpilers"> <div class="card-body"> - <h5><i class="bi bi-filetype-tsx" aria-hidden="true"></i> TypeScript Integration</h5> + <h5><i class="bi bi-arrow-left-right" aria-hidden="true"></i> Transpilers (Babel)</h5> <div class="card-content-wrapper"> - <p class="summary"><span class="term">TypeScript</span> adds static typing to JS. Improves code maintainability and reduces runtime errors. Integrates well with frameworks and build tools. <a href="https://www.typescriptlang.org/docs/" target="_blank">TypeScript Docs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingTs" aria-expanded="false" aria-controls="collapseToolingTs"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary"><span class="term">Babel</span> converts modern JS (ES6+) or syntax extensions (JSX, TypeScript drafts) into backward-compatible versions for older browsers/environments. <a href="https://babeljs.io/" target="_blank">Babel Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingTranspilers" aria-expanded="false" aria-controls="collapseToolingTranspilers"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseToolingTs"> - <h6>Benefits</h6> + <div class="collapse collapse-content" id="collapseToolingTranspilers"> + <h6>Purpose</h6> <ul> - <li><strong>Early Error Detection:</strong> Catch type errors during development, not at runtime.</li> - <li><strong>Improved Readability & Maintainability:</strong> Types make code easier to understand and refactor.</li> - <li><strong>Better Tooling:</strong> Enhanced autocompletion, refactoring, and navigation in IDEs.</li> + <li>Use latest JavaScript features without waiting for full browser support.</li> + <li>Transform syntax extensions like JSX into valid JavaScript.</li> + <li>Can polyfill missing features (using `core-js`).</li> </ul> <h6>Core Concepts</h6> <ul> - <li><strong>Basic Types:</strong> `string`, `number`, `boolean`, `any`, `unknown`, `void`, `null`, `undefined`.</li> - <li><strong>Interfaces & Types:</strong> Define shapes of objects.</li> - <li><strong>Generics:</strong> Create reusable components that can work over a variety of types.</li> - <li><strong>`tsconfig.json`:</strong> Compiler options for the TypeScript project.</li> + <li><strong>Presets:</strong> Pre-defined sets of plugins (e.g., `@babel/preset-env` for latest JS, `@babel/preset-react` for JSX, `@babel/preset-typescript`).</li> + <li><strong>Plugins:</strong> Handle specific transformations (e.g., `@babel/plugin-transform-arrow-functions`).</li> + <li><strong>Configuration:</strong> Usually via `babel.config.js` or `.babelrc` file.</li> + <li><strong>Integration:</strong> Used within build tools (Webpack loaders, Vite plugins) or run via CLI.</li> </ul> - <p><em>Setup examples with React/Vue and common patterns needed.</em></p> + <h6>`@babel/preset-env`</h6> + <p>Key preset that automatically determines necessary transformations and polyfills based on target browsers (often configured via `browserslist`).</p> + <p><em>Note: Vite handles TS/JSX transformation out-of-the-box during dev using esbuild, and uses Babel/Rollup plugins for production builds if needed. Webpack typically relies more heavily on Babel loaders.</em></p> </div> </div> </div> - <div class="col-lg-4 col-md-6"> - <div class="info-card card-tooling" id="card-tooling-testing"> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-tooling" id="card-tooling-linters"> <!-- Updated --> <div class="card-body"> - <h5><i class="bi bi-clipboard2-check" aria-hidden="true"></i> Testing Frameworks</h5> + <h5><i class="bi bi-check2-square" aria-hidden="true"></i> Linters & Formatters</h5> <div class="card-content-wrapper"> - <p class="summary">Verify code correctness. <span class="term">Jest</span> / <span class="term">Vitest</span> for unit/integration. <span class="term">React Testing Library</span> for component tests. <span class="term">Cypress</span> / <span class="term">Playwright</span> for E2E tests. <a href="https://jestjs.io/" target="_blank">Jest</a> | <a href="https://testing-library.com/" target="_blank">Testing Library</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingTesting" aria-expanded="false" aria-controls="collapseToolingTesting"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary"><span class="term">ESLint</span> finds errors/style issues. <span class="term">Prettier</span> enforces consistent code style automatically. Essential for code quality and team collaboration. <a href="https://eslint.org/" target="_blank">ESLint</a> | <a href="https://prettier.io/" target="_blank">Prettier</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingLinters" aria-expanded="false" aria-controls="collapseToolingLinters"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseToolingTesting"> - <h6>Types of Tests</h6> + <div class="collapse collapse-content" id="collapseToolingLinters"> + <h6>ESLint</h6> <ul> - <li><strong>Unit Tests:</strong> Test individual functions or small pieces of code in isolation. (e.g., Jest, Vitest, Mocha, Jasmine).</li> - <li><strong>Integration Tests:</strong> Test how multiple units work together.</li> - <li><strong>Component Tests:</strong> Test UI components in isolation, focusing on user interaction. (e.g., React Testing Library, Vue Testing Library).</li> - <li><strong>End-to-End (E2E) Tests:</strong> Test the entire application flow from the user's perspective in a real browser. (e.g., Cypress, Playwright, Puppeteer).</li> + <li><strong>Purpose:</strong> Static analysis to find potential bugs, enforce coding standards, identify anti-patterns.</li> + <li><strong>Configuration:</strong> Via `.eslintrc.js`, `.eslintrc.json`, etc. Specify parser (e.g., `@typescript-eslint/parser`), plugins (e.g., `eslint-plugin-react`), rules, and extends (e.g., `eslint:recommended`, `plugin:react/recommended`).</li> + <li><strong>Rules:</strong> Granular control over specific checks (e.g., `no-unused-vars`, `eqeqeq`). Can be turned off, set to warn, or error.</li> + <li><strong>Fixing:</strong> Can automatically fix some reported issues (`--fix` flag).</li> </ul> - <h6>Popular Tools</h6> + <h6>Prettier</h6> + <ul> + <li><strong>Purpose:</strong> Opinionated code formatter. Parses code and re-prints it according to its consistent style rules. Focuses purely on formatting, not code quality rules.</li> + <li><strong>Configuration:</strong> Minimal options via `.prettierrc.js`, etc. (e.g., `tabWidth`, `semi`, `singleQuote`).</li> + <li><strong>Integration:</strong> Often used with ESLint via `eslint-plugin-prettier` (runs Prettier as an ESLint rule) and `eslint-config-prettier` (disables ESLint rules that conflict with Prettier).</li> + <li><strong>Usage:</strong> Run via CLI, integrate with IDEs (format on save), use in pre-commit hooks (with tools like Husky/lint-staged).</li> + </ul> + <p><em>Using ESLint for code quality/errors and Prettier for formatting is a common and effective combination.</em></p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-tooling" id="card-tooling-node"> + <div class="card-body"> + <h5><i class="bi bi-motherboard" aria-hidden="true"></i> Node.js (Frontend Tooling)</h5> + <div class="card-content-wrapper"> + <p class="summary"><span class="term">Node.js</span> runtime is essential for the frontend ecosystem. Powers package managers (npm), build tools (Vite, Webpack), task runners, linters, testing frameworks. <a href="https://nodejs.org/" target="_blank">Node.js</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingNode" aria-expanded="false" aria-controls="collapseToolingNode"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseToolingNode"> + <h6>Role in Frontend Development</h6> <ul> - <li><strong>Jest / Vitest:</strong> Popular test runners with built-in assertion libraries and mocking capabilities. Vitest is Vite-native and fast.</li> - <li><strong>Testing Library (RTL, VTL):</strong> Encourages testing components by interacting with them as a user would.</li> - <li><strong>Mocking Libraries:</strong> Jest has built-in mocking. Sinon.JS is another option.</li> + <li><strong>Runtime Environment:</strong> Executes the JavaScript code of build tools, linters, test runners, etc., outside the browser.</li> + <li><strong>Package Management:</strong> npm (Node Package Manager) is bundled with Node.js, enabling installation and management of project dependencies.</li> + <li><strong>Build Process:</strong> Bundlers like Webpack and Vite are Node.js applications.</li> + <li><strong>Server-Side Rendering (SSR):</strong> Frameworks like Next.js and Nuxt.js run on Node.js to render pages on the server.</li> + <li><strong>API Mocking/Development Servers:</strong> Tools for creating local development servers often run on Node.js.</li> </ul> - <p><em>Basic assertion examples for Jest/Vitest needed.</em></p> + <p>While frontend code ultimately runs in the browser, the entire development toolchain relies heavily on Node.js. Use Node Version Manager (<a href="https://github.com/nvm-sh/nvm" target="_blank">nvm</a>) to manage multiple Node versions easily.</p> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-tooling" id="card-tooling-devtools"> + <div class="info-card card-tooling" id="card-tooling-devtools"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-tools" aria-hidden="true"></i> Browser DevTools</h5> <div class="card-content-wrapper"> - <p class="summary">Essential suite of tools built into browsers for debugging, inspecting DOM/CSS, performance profiling, network analysis, and more. <a href="https://developer.chrome.com/docs/devtools/" target="_blank">Chrome DevTools</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingDevtools" aria-expanded="false" aria-controls="collapseToolingDevtools"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Essential tools in browsers (Chrome, Firefox, Edge) for debugging, inspection (DOM/CSS), profiling, network analysis. Crucial for frontend development. <a href="https://developer.chrome.com/docs/devtools/" target="_blank">Chrome DevTools</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingDevtools" aria-expanded="false" aria-controls="collapseToolingDevtools"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseToolingDevtools"> - <h6>Key Panels</h6> + <h6>Key Panels & Uses</h6> + <ul> + <li><strong>Elements:</strong> Inspect/edit live DOM tree, view/edit CSS styles, check computed styles, accessibility properties.</li> + <li><strong>Console:</strong> View `console.log/warn/error` messages, execute JS snippets, inspect JS objects, monitor events.</li> + <li><strong>Sources:</strong> Set breakpoints, step through JS code, inspect call stack and scope variables, view source maps.</li> + <li><strong>Network:</strong> Inspect HTTP requests/responses (headers, body, timing), filter requests, throttle network speed, block requests.</li> + <li><strong>Performance:</strong> Record and analyze runtime performance (JS execution, rendering, painting), identify bottlenecks, detect layout shifts.</li> + <li><strong>Memory:</strong> Profile memory usage, detect memory leaks, analyze heap snapshots.</li> + <li><strong>Application:</strong> Inspect/manage storage (localStorage, sessionStorage, IndexedDB, cookies), service workers, manifest files, cache storage.</li> + <li><strong>Lighthouse:</strong> (Chrome) Run audits for Performance, Accessibility, Best Practices, SEO, PWA readiness.</li> + </ul> + <h6>Framework Extensions</h6> + <p>Install browser extensions like React Developer Tools, Vue.js devtools, Angular DevTools for framework-specific inspection (component hierarchy, state, props).</p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-tooling" id="card-tooling-testing"> <!-- Updated --> + <div class="card-body"> + <h5><i class="bi bi-clipboard2-check" aria-hidden="true"></i> Testing Frameworks</h5> + <div class="card-content-wrapper"> + <p class="summary">Verify code correctness. <span class="term">Jest/Vitest</span> (Unit/Integration), <span class="term">Testing Library</span> (Components), <span class="term">Cypress/Playwright</span> (E2E). Essential for robust applications. <a href="https://jestjs.io/" target="_blank">Jest</a> | <a href="https://testing-library.com/" target="_blank">Testing Library</a> | <a href="https://playwright.dev/" target="_blank">Playwright</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingTesting" aria-expanded="false" aria-controls="collapseToolingTesting"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseToolingTesting"> + <h6>Levels of Testing</h6> + <ul> + <li><strong>Unit Tests:</strong> Isolate and test small units (functions, modules). Fast, easy to write. Use test runners like Jest, Vitest, Mocha.</li> + <li><strong>Integration Tests:</strong> Test interactions between multiple units/modules.</li> + <li><strong>Component Tests:</strong> Test UI components visually or by simulating user interaction. Focus on behavior, not implementation details. Use Testing Library (React, Vue, Svelte, etc.) with Jest/Vitest.</li> + <li><strong>End-to-End (E2E) Tests:</strong> Automate browser interaction to test complete user flows. Slower, more brittle, but essential for critical paths. Use Cypress, Playwright.</li> + </ul> + <h6>Key Tools & Libraries</h6> <ul> - <li><strong>Elements:</strong> Inspect and edit the DOM tree and CSS styles.</li> - <li><strong>Console:</strong> View logs, run JavaScript commands, interact with the page.</li> - <li><strong>Sources:</strong> Debug JavaScript code (breakpoints, call stack, watch expressions).</li> - <li><strong>Network:</strong> Inspect network requests and responses.</li> - <li><strong>Performance:</strong> Profile runtime performance, identify bottlenecks.</li> - <li><strong>Application:</strong> Inspect storage (localStorage, sessionStorage, cookies), service workers, manifest.</li> - <li><strong>Lighthouse:</strong> (In Chrome) Audit for performance, accessibility, SEO, PWA.</li> + <li><strong>Test Runners:</strong> Jest, Vitest (Vite-native), Mocha, Jasmine. Provide test structure (`describe`, `it`/`test`), assertions, mocking.</li> + <li><strong>Assertion Libraries:</strong> Built into Jest/Vitest. Chai is popular standalone.</li> + <li><strong>Mocking/Stubbing:</strong> Jest built-ins, Sinon.JS. Replace dependencies for isolated testing.</li> + <li><strong>Testing Library:</strong> Family of libraries (`@testing-library/react`, etc.) promoting testing components via user interactions, querying by accessible roles/text.</li> + <li><strong>E2E Tools:</strong> Cypress (runs in browser), Playwright (controls browser externally, cross-browser).</li> </ul> - <p><em>Framework-specific DevTools extensions (React DevTools, Vue Devtools) are also invaluable.</em></p> + <pre><code class="language-javascript">// Example Jest/Vitest Unit Test +function sum(a, b) { return a + b; } + +test('adds 1 + 2 to equal 3', () => { + expect(sum(1, 2)).toBe(3); +}); + +// Example React Testing Library Component Test +// import { render, screen, fireEvent } from '@testing-library/react'; +// import Counter from './Counter'; +// test('increments counter on click', () => { +// render(<Counter />); +// const button = screen.getByRole('button', { name: /click me/i }); +// const countDisplay = screen.getByText(/you clicked 0 times/i); +// fireEvent.click(button); +// expect(countDisplay).toHaveTextContent(/you clicked 1 time/i); +// }); +</code></pre> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-tooling" id="card-tooling-linters"> + <div class="info-card card-tooling" id="card-tooling-ts"> <!-- Updated - Placed TS here as Tooling --> <div class="card-body"> - <h5><i class="bi bi-check2-square" aria-hidden="true"></i> Linters & Formatters</h5> + <h5><i class="bi bi-filetype-tsx" aria-hidden="true"></i> TypeScript Integration</h5> <div class="card-content-wrapper"> - <p class="summary"><span class="term">ESLint</span> analyzes code for potential errors and style issues. <span class="term">Prettier</span> automatically formats code for consistent style. Improves code quality and team consistency. <a href="https://eslint.org/" target="_blank">ESLint</a> | <a href="https://prettier.io/" target="_blank">Prettier</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingLinters" aria-expanded="false" aria-controls="collapseToolingLinters"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary"><span class="term">TypeScript</span> adds static typing to JS. Improves maintainability, catches errors early. Transpiled to JS via TSC or build tools. <a href="https://www.typescriptlang.org/docs/" target="_blank">TypeScript Docs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseToolingTs" aria-expanded="false" aria-controls="collapseToolingTs"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> - <div class="collapse collapse-content" id="collapseToolingLinters"> - <h6>ESLint</h6> + <div class="collapse collapse-content" id="collapseToolingTs"> + <h6>Benefits</h6> <ul> - <li>Static analysis tool to find problematic patterns or code that doesn't adhere to style guidelines.</li> - <li>Configurable with rules (e.g., `.eslintrc.js`).</li> - <li>Plugins for specific frameworks (e.g., `eslint-plugin-react`) and TypeScript (`@typescript-eslint/parser`).</li> + <li>Catch type errors during development (compile-time).</li> + <li>Improved code readability and self-documentation.</li> + <li>Enhanced IDE support (autocompletion, refactoring).</li> + <li>Better maintainability for large projects/teams.</li> </ul> - <h6>Prettier</h6> + <h6>Core Concepts</h6> <ul> - <li>Opinionated code formatter. Parses code and re-prints it with consistent style.</li> - <li>Integrates well with ESLint (e.g., `eslint-config-prettier` to turn off conflicting ESLint style rules).</li> - <li>Often run on save in IDEs or as a pre-commit hook.</li> + <li><strong>Type Annotations:</strong> `let name: string = "Alice";`, `function greet(user: { name: string }): void { ... }`</li> + <li><strong>Interfaces & Types:</strong> Define custom shapes for objects: `interface User { id: number; name: string; }`, `type Point = { x: number; y: number; };`</li> + <li><strong>Generics:</strong> Create reusable components/functions working over various types: `function identity<T>(arg: T): T { return arg; }`</li> + <li><strong>Utility Types:</strong> `Partial<T>`, `Required<T>`, `Readonly<T>`, `Pick<T, K>`, `Omit<T, K>`, etc.</li> + <li><strong>Enums:</strong> Named sets of numeric or string constants.</li> + <li><strong>Type Inference:</strong> TS often infers types automatically.</li> </ul> - <p><em>Using both together provides powerful code quality enforcement.</em></p> + <h6>Setup & Configuration (`tsconfig.json`)</h6> + <p>The `tsconfig.json` file configures the TS compiler (`tsc`). Key options include `target` (output JS version), `module` (module system), `strict` (enables strict type checks), `jsx` (JSX processing), `outDir`, `rootDir`.</p> + <h6>Integration</h6> + <p>Most modern frameworks (React, Vue, Angular, Svelte) have excellent TypeScript support. Build tools (Vite, Webpack) integrate TS compilation seamlessly.</p> </div> </div> </div> @@ -1567,121 +2496,284 @@ function Controls() { <h2 class="section-title" id="section-advanced-title">Advanced Concepts & Patterns</h2> <div class="row"> <div class="col-lg-4 col-md-6"> - <div class="info-card card-advanced" id="card-advanced-perf"> + <div class="info-card card-advanced" id="card-advanced-perf"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-speedometer2" aria-hidden="true"></i> Performance Optimization</h5> <div class="card-content-wrapper"> - <p class="summary">Techniques to improve load times and runtime speed. Includes <span class="term">code splitting</span>, <span class="term">lazy loading</span> components/routes, <span class="term">memoization</span> (React.memo, useMemo). <a href="https://web.dev/performance/" target="_blank">web.dev Performance</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedPerf" aria-expanded="false" aria-controls="collapseAdvancedPerf"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Techniques for faster load/runtime. Includes <span class="term">code splitting</span>, <span class="term">lazy loading</span>, <span class="term">memoization</span>, image optimization, <span class="term">virtualization</span>, efficient data fetching. <a href="https://web.dev/performance/" target="_blank">web.dev Performance</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedPerf" aria-expanded="false" aria-controls="collapseAdvancedPerf"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseAdvancedPerf"> - <h6>Key Techniques</h6> + <h6>Loading Performance</h6> <ul> - <li><strong>Code Splitting:</strong> Breaking down large bundles into smaller chunks that can be loaded on demand. (Webpack, Vite support this).</li> - <li><strong>Lazy Loading:</strong> Deferring the loading of non-critical resources (images, components, routes) until they are needed. (e.g., `React.lazy`, dynamic `import()`).</li> - <li><strong>Memoization:</strong> Caching results of expensive function calls and re-using them if inputs haven't changed. (e.g., `React.memo`, `useMemo`, `useCallback` in React).</li> - <li><strong>Virtualization (Windowing):</strong> Rendering only visible items in long lists or large tables to improve performance. (e.g., `react-window`, `react-virtualized`).</li> - <li><strong>Tree Shaking:</strong> Bundlers remove unused code from the final bundle.</li> - <li><strong>Optimizing Images:</strong> Compression, responsive images (`<picture>`, `srcset`), modern formats (WebP, AVIF).</li> - <li><strong>Caching:</strong> Browser caching, CDN caching.</li> + <li><strong>Code Splitting:</strong> Break large JS bundles into smaller chunks loaded on demand (route-based or component-based). Supported by modern bundlers.</li> + <li><strong>Lazy Loading:</strong> Defer loading non-critical resources (components via `React.lazy`/dynamic `import()`, images via `loading="lazy"` attribute).</li> + <li><strong>Tree Shaking:</strong> Bundler removes unused code. Ensure code is statically analyzable (use ESM).</li> + <li><strong>Minification/Compression:</strong> Reduce file sizes (Terser for JS, CSSNano, Brotli/Gzip on server).</li> + <li><strong>Image Optimization:</strong> Use appropriate formats (WebP, AVIF), compression, responsive images (`srcset`, `<picture>`).</li> + <li><strong>Critical CSS:</strong> Inline essential CSS for initial render.</li> + <li><strong>Caching:</strong> Leverage browser caching (HTTP headers) and CDNs.</li> + <li><strong>Preloading/Prefetching:</strong> Hint browser about resources needed soon (`<link rel=preload/prefetch>`).</li> </ul> - <p><em>Measure performance with Browser DevTools (Performance, Lighthouse tabs) and Core Web Vitals.</em></p> + <h6>Runtime Performance</h6> + <ul> + <li><strong>Memoization:</strong> Avoid recomputing expensive values or re-rendering components if props/inputs haven't changed (`React.memo`, `useMemo`, `useCallback`).</li> + <li><strong>Virtualization (Windowing):</strong> Render only visible items in long lists/tables (`react-window`, `tanstack-virtual`).</li> + <li><strong>Debouncing/Throttling:</strong> Limit frequency of expensive event handlers (e.g., scroll, resize).</li> + <li><strong>Efficient DOM Updates:</strong> Minimize direct DOM manipulation (frameworks help). Avoid layout thrashing.</li> + <li><strong>Web Workers:</strong> Offload CPU-intensive tasks from the main thread.</li> + <li><strong>Optimizing Data Fetching:</strong> Avoid waterfalls, use caching (React Query, SWR).</li> + </ul> + <p><em>Measure using DevTools (Performance, Lighthouse), WebPageTest, Core Web Vitals.</em></p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-advanced" id="card-advanced-web-perf-metrics"> + <div class="card-body"> + <h5><i class="bi bi-graph-up" aria-hidden="true"></i> Web Performance Metrics</h5> + <div class="card-content-wrapper"> + <p class="summary">Quantify user experience. Key metrics include <span class="term">Core Web Vitals</span> (LCP, FID/INP, CLS), TTFB, FCP. Measured via lab (Lighthouse) & field (RUM) data. <a href="https://web.dev/vitals/" target="_blank">web.dev Vitals</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedWebPerfMetrics" aria-expanded="false" aria-controls="collapseAdvancedWebPerfMetrics"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseAdvancedWebPerfMetrics"> + <h6>Core Web Vitals (CWV)</h6> + <ul> + <li><strong>Largest Contentful Paint (LCP):</strong> Loading performance. Time to render the largest image or text block visible within the viewport. (Good: <= 2.5s)</li> + <li><strong>First Input Delay (FID) / Interaction to Next Paint (INP):</strong> Interactivity. FID measures delay from first interaction to browser response (Good: <= 100ms). INP (newer, replacing FID) measures overall responsiveness to interactions. (Good: <= 200ms)</li> + <li><strong>Cumulative Layout Shift (CLS):</strong> Visual stability. Measures unexpected layout shifts during page lifespan. (Good: <= 0.1)</li> + </ul> + <h6>Other Important Metrics</h6> + <ul> + <li><strong>Time to First Byte (TTFB):</strong> Server responsiveness. Time between request and first byte of response.</li> + <li><strong>First Contentful Paint (FCP):</strong> Perceived load speed. Time until *any* content (text, image) is rendered.</li> + <li><strong>Time to Interactive (TTI):</strong> Load responsiveness. Time until page is visually rendered *and* reliably responsive to user input.</li> + </ul> + <h6>Measurement</h6> + <ul> + <li><strong>Lab Data:</strong> Controlled environment testing (Lighthouse in DevTools, WebPageTest). Good for debugging.</li> + <li><strong>Field Data (Real User Monitoring - RUM):</strong> Data from actual users (Chrome User Experience Report - CrUX, analytics tools). Reflects real-world performance.</li> + </ul> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-advanced" id="card-advanced-security"> + <div class="card-body"> + <h5><i class="bi bi-shield-lock" aria-hidden="true"></i> Security Best Practices</h5> + <div class="card-content-wrapper"> + <p class="summary">Protect against common web vulnerabilities like <span class="term">XSS</span> (Cross-Site Scripting), <span class="term">CSRF</span> (Cross-Site Request Forgery). Sanitize inputs, use secure headers, manage dependencies. <a href="https://owasp.org/www-project-top-ten/" target="_blank">OWASP Top 10</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedSecurity" aria-expanded="false" aria-controls="collapseAdvancedSecurity"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseAdvancedSecurity"> + <h6>Common Frontend Vulnerabilities & Mitigations</h6> + <ul> + <li><strong>Cross-Site Scripting (XSS):</strong> Injecting malicious scripts into content shown to other users. + <ul> + <li><strong>Mitigation:</strong> Properly encode/escape user-generated content before rendering. Avoid `innerHTML` with untrusted data. Use framework's built-in sanitation (React auto-escapes). Implement Content Security Policy (CSP) header. Use libraries like DOMPurify for sanitizing HTML.</li> + </ul> + </li> + <li><strong>Cross-Site Request Forgery (CSRF):</strong> Tricking a logged-in user's browser into making an unwanted request to a site they're authenticated on. + <ul> + <li><strong>Mitigation:</strong> Primarily server-side concern. Use anti-CSRF tokens (Synchronizer Token Pattern). Check `Origin` / `Referer` headers (less reliable). Use `SameSite` cookie attribute (`Lax` or `Strict`).</li> + </ul> + </li> + <li><strong>Insecure Direct Object References (IDOR):</strong> Exposing internal implementation objects (like file paths or database keys) that allow attackers to manipulate references. (More backend, but frontend can expose IDs).</li> + <li><strong>Clickjacking:</strong> Tricking users into clicking something different from what they perceive. + <ul><li><strong>Mitigation:</strong> Use `X-Frame-Options` or CSP `frame-ancestors` header to prevent embedding in malicious frames.</li></ul> + </li> + <li><strong>Dependency Vulnerabilities:</strong> Using third-party libraries with known security flaws. + <ul><li><strong>Mitigation:</strong> Regularly audit dependencies (`npm audit`, `yarn audit`). Keep packages updated. Use tools like Snyk.</li></ul> + </li> + </ul> + <h6>General Practices</h6> + <ul> + <li>Validate and sanitize all user input (client-side validation is for UX, server-side is crucial).</li> + <li>Use HTTPS everywhere.</li> + <li>Implement appropriate Content Security Policy (CSP).</li> + <li>Securely handle authentication tokens (e.g., store in `HttpOnly`, `Secure`, `SameSite` cookies or secure browser storage with caution).</li> + <li>Don't expose sensitive data or API keys in frontend code.</li> + </ul> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-advanced" id="card-advanced-a11y"> + <div class="info-card card-advanced" id="card-advanced-a11y"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-person-check" aria-hidden="true"></i> Accessibility (a11y)</h5> <div class="card-content-wrapper"> - <p class="summary">Designing web applications usable by everyone, including people with disabilities. Use <span class="term">semantic HTML</span>, <span class="term">ARIA attributes</span>, ensure keyboard navigation, color contrast. <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility" target="_blank">MDN Accessibility</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedA11y" aria-expanded="false" aria-controls="collapseAdvancedA11y"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Design usable web apps for everyone, including those with disabilities. Use <span class="term">semantic HTML</span>, <span class="term">ARIA</span>, ensure keyboard navigation, focus management, color contrast. <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility" target="_blank">MDN Accessibility</a> | <a href="https://www.w3.org/WAI/standards-guidelines/wcag/" target="_blank">WCAG</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedA11y" aria-expanded="false" aria-controls="collapseAdvancedA11y"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseAdvancedA11y"> - <h6>Key Principles (WCAG)</h6> - <p>Perceivable, Operable, Understandable, Robust.</p> - <h6>Practical Steps</h6> + <h6>Key Principles (WCAG - POUR)</h6> + <ul> + <li><strong>Perceivable:</strong> Information must be presentable to users in ways they can perceive (e.g., alt text for images, captions for videos, sufficient contrast).</li> + <li><strong>Operable:</strong> UI components and navigation must be operable (e.g., keyboard accessibility, sufficient time, no seizure triggers, clear navigation).</li> + <li><strong>Understandable:</strong> Information and operation of UI must be understandable (e.g., clear language, predictable behavior, input assistance).</li> + <li><strong>Robust:</strong> Content must be robust enough to be interpreted reliably by a wide variety of user agents, including assistive technologies.</li> + </ul> + <h6>Practical Steps for Developers</h6> <ul> - <li><strong>Semantic HTML:</strong> Use HTML elements for their intended purpose (e.g., `<button>`, `<nav>`, `<main>`).</li> - <li><strong>ARIA (Accessible Rich Internet Applications):</strong> Use `role` and `aria-*` attributes to provide additional semantics for assistive technologies when native HTML is insufficient.</li> - <li><strong>Keyboard Navigation:</strong> Ensure all interactive elements are focusable and operable via keyboard. Manage focus order.</li> - <li><strong>Focus Management:</strong> Visually indicate focused elements. Programmatically manage focus in dynamic UIs.</li> - <li><strong>Alternative Text:</strong> Provide `alt` text for images.</li> - <li><strong>Color Contrast:</strong> Ensure sufficient contrast between text and background.</li> - <li><strong>Forms:</strong> Associate labels with inputs (`<label for="...">`). Provide clear error messages.</li> - <li><strong>Testing:</strong> Use automated tools (e.g., Axe, Lighthouse), manual keyboard testing, screen reader testing.</li> + <li><strong>Semantic HTML:</strong> Use elements like `<button>`, `<nav>`, `<main>`, `<input type="email">` correctly. Avoid using `<div>` or `<span>` for interactive elements without adding ARIA roles and keyboard handlers.</li> + <li><strong>ARIA Roles & Attributes:</strong> Use `role="..."` and `aria-*="..."` attributes to add semantics for assistive tech when native HTML is insufficient (e.g., custom widgets, dynamic content updates `aria-live`). Use sparingly and correctly. <a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA" target="_blank">ARIA Docs</a></li> + <li><strong>Keyboard Navigation:</strong> All interactive elements must be reachable and operable using the Tab key (and Shift+Tab), Enter, Spacebar. Ensure logical focus order.</li> + <li><strong>Focus Management:</strong> Provide clear visual focus indicators (`:focus-visible`). Programmatically manage focus in SPAs after route changes or modal dialogs appear.</li> + <li><strong>Forms & Labels:</strong> Always associate `<label>` elements with form controls using `for`/`id` or by wrapping. Provide clear instructions and error messages (associate errors with inputs using `aria-describedby`).</li> + <li><strong>Images & Media:</strong> Provide descriptive `alt` text for meaningful images. Provide captions and transcripts for audio/video.</li> + <li><strong>Color Contrast:</strong> Ensure sufficient contrast ratio (WCAG AA: 4.5:1 for normal text, 3:1 for large text). Use tools to check.</li> + <li><strong>Testing:</strong> Automated tools (Axe, Lighthouse), manual keyboard testing, screen reader testing (NVDA, VoiceOver, JAWS).</li> </ul> </div> </div> </div> <div class="col-lg-4 col-md-6"> - <div class="info-card card-advanced" id="card-advanced-pwa"> + <div class="info-card card-advanced" id="card-advanced-pwa"> <!-- Updated --> <div class="card-body"> <h5><i class="bi bi-phone" aria-hidden="true"></i> Progressive Web Apps (PWAs)</h5> <div class="card-content-wrapper"> - <p class="summary">Web apps that use modern web capabilities to deliver an app-like experience. Key features: installable, offline support (via <span class="term">Service Workers</span>), push notifications. <a href="https://web.dev/progressive-web-apps/" target="_blank">web.dev PWAs</a></p> - <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedPwa" aria-expanded="false" aria-controls="collapseAdvancedPwa"> - Details <i class="bi bi-chevron-down"></i> - </button> + <p class="summary">Web apps using modern APIs for app-like experience: installable, offline capable (<span class="term">Service Workers</span>), reliable. Requires HTTPS, Manifest. <a href="https://web.dev/progressive-web-apps/" target="_blank">web.dev PWAs</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedPwa" aria-expanded="false" aria-controls="collapseAdvancedPwa"> Details <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseAdvancedPwa"> <h6>Core Technologies</h6> <ul> - <li><strong>Service Workers:</strong> Scripts that run in the background, separate from the web page. Enable caching for offline support, background sync, push notifications.</li> - <li><strong>Web App Manifest:</strong> JSON file describing the app (name, icons, start URL, display mode) to make it installable.</li> - <li><strong>HTTPS:</strong> Required for Service Workers and other PWA features.</li> + <li><strong>Service Workers:</strong> JS scripts acting as proxy servers between browser and network. Run in background. Key for offline caching (Cache Storage API), push notifications, background sync. <a href="https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API" target="_blank">Service Workers</a></li> + <li><strong>Web App Manifest (`manifest.json`):</strong> JSON file providing app information (name, icons, start URL, display mode, theme color) allowing installation to home screen/desktop. <a href="https://developer.mozilla.org/en-US/docs/Web/Manifest" target="_blank">Web App Manifest</a></li> + <li><strong>HTTPS:</strong> Required for Service Workers and installability prompts.</li> + </ul> + <h6>Key Capabilities & Benefits</h6> + <ul> + <li><strong>Installable:</strong> Users can add the PWA to their home screen/app list.</li> + <li><strong>Offline Capable:</strong> Service workers cache assets/data, allowing app to work without network connection (or under poor conditions).</li> + <li><strong>App-like Feel:</strong> Can run in standalone window (`display: standalone`), use device features.</li> + <li><strong>Discoverable & Linkable:</strong> Still a web app, discoverable via search engines, shareable via URL.</li> + <li><strong>Engaging:</strong> Can receive Push Notifications (Push API + Service Worker).</li> + <li><strong>Always Up-to-date:</strong> Service worker update process allows background updates.</li> + </ul> + <p>Framework CLIs (Create React App, Angular CLI, Vue CLI) often provide PWA setup options. Libraries like Workbox simplify service worker implementation.</p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-advanced" id="card-advanced-ssr-ssg"> + <div class="card-body"> + <h5><i class="bi bi-server" aria-hidden="true"></i> SSR / SSG / CSR</h5> + <div class="card-content-wrapper"> + <p class="summary">Rendering Strategies: <span class="term">CSR</span> (Client-Side), <span class="term">SSR</span> (Server-Side Rendering), <span class="term">SSG</span> (Static Site Generation). Impact SEO, performance (TTFB, FCP, TTI). Meta-frameworks help. <a href="https://web.dev/rendering-on-the-web/" target="_blank">web.dev Rendering</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedSsr" aria-expanded="false" aria-controls="collapseAdvancedSsr"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseAdvancedSsr"> + <h6>Rendering Strategies</h6> + <ul> + <li><strong>Client-Side Rendering (CSR):</strong> Default for many SPAs (React, Vue, Angular basic setup). Browser downloads minimal HTML + JS bundle. JS fetches data and renders content in the browser. + <ul><li>Pros: Rich interactivity after load, cheaper hosting.</li><li>Cons: Slow initial load (blank screen), poor SEO without workarounds, requires JS.</li></ul> + </li> + <li><strong>Server-Side Rendering (SSR):</strong> Render page HTML on the server for each request. Browser receives full HTML content, then "hydrates" (attaches event listeners, makes it interactive). + <ul><li>Pros: Faster FCP/LCP, better SEO, works without JS initially.</li><li>Cons: Slower TTFB (server work), more complex server setup, full page reload on navigation (unless paired with client-side routing).</li></ul> + </li> + <li><strong>Static Site Generation (SSG):</strong> Pre-render all pages to static HTML files at build time. Serve files directly from CDN. + <ul><li>Pros: Fastest possible TTFB/FCP/LCP, best SEO, secure, cheap hosting.</li><li>Cons: Requires rebuild for content changes, not suitable for highly dynamic/personalized content per request.</li></ul> + </li> + <li><strong>Incremental Static Regeneration (ISR):</strong> (Next.js feature) Like SSG, but pages can be regenerated automatically in the background after deployment on a timer or upon request, offering a balance.</li> + <li><strong>Streaming SSR:</strong> Send HTML in chunks as it's rendered on the server, improving TTFB/FCP.</li> + </ul> + <h6>Meta-Frameworks</h6> + <p>Frameworks built on top of UI libraries (React, Vue, Svelte) that provide integrated solutions for routing, data fetching, and rendering strategies:</p> + <ul> + <li><strong>Next.js (React):</strong> Supports SSR, SSG, ISR, API Routes, Routing.</li> + <li><strong>Nuxt (Vue):</strong> Supports SSR, SSG, API Routes, Routing.</li> + <li><strong>SvelteKit (Svelte):</strong> Supports SSR, SSG, API Routes, Routing.</li> + <li><strong>Remix (React):</strong> Focuses on web standards, SSR, nested routing, data loading/mutations.</li> + <li><strong>Astro:</strong> Content-focused sites, partial hydration ("Islands Architecture"), framework-agnostic.</li> </ul> - <h6>Benefits</h6> + <p><em>Choice depends on content dynamism, SEO needs, performance goals, infrastructure.</em></p> + </div> + </div> + </div> + <div class="col-lg-4 col-md-6"> + <div class="info-card card-advanced" id="card-advanced-design-patterns"> + <div class="card-body"> + <h5><i class="bi bi-bricks" aria-hidden="true"></i> Design Patterns in JS</h5> + <div class="card-content-wrapper"> + <p class="summary">Reusable solutions to common programming problems. Includes Creational (Singleton), Structural (Module, Facade), Behavioral (Observer, Command) patterns adapted for JS. <a href="https://refactoring.guru/design-patterns/javascript" target="_blank">Refactoring Guru (JS)</a></p> + <button class="btn btn-sm details-toggle" type="button" data-bs-toggle="collapse" data-bs-target="#collapseAdvancedPatterns" aria-expanded="false" aria-controls="collapseAdvancedPatterns"> Details <i class="bi bi-chevron-down"></i> </button> + </div> + </div> + <div class="collapse collapse-content" id="collapseAdvancedPatterns"> + <h6>Common Patterns (Examples)</h6> <ul> - <li><strong>Reliable:</strong> Load instantly, even in uncertain network conditions.</li> - <li><strong>Fast:</strong> Respond quickly to user interactions.</li> - <li><strong>Engaging:</strong> Feel like a native app, installable, push notifications.</li> + <li><strong>Module Pattern:</strong> Encapsulate private state/methods using closures or ES Modules. + <pre><code class="language-javascript">// Using IIFE (older) +const counterModule = (function() { + let count = 0; // Private + function _increment() { count++; } // Private + return { + increment: () => { _increment(); console.log(count); }, + getCount: () => count + }; +})(); +counterModule.increment(); // 1 + +// Using ES Modules (preferred) +// counter.js +let count = 0; +function _increment() { count++; } +export function increment() { _increment(); console.log(count); } +export function getCount() { return count; } +// import { increment } from './counter.js'; +</code></pre> + </li> + <li><strong>Singleton Pattern:</strong> Ensure a class has only one instance and provide a global point of access. (Less common in JS due to modules, but can be used for global config/state).</li> + <li><strong>Observer Pattern:</strong> Define a one-to-many dependency where observers are notified of state changes in a subject. (Foundation for event listeners, reactive systems like RxJS).</li> + <li><strong>Facade Pattern:</strong> Provide a simplified interface to a complex subsystem.</li> + <li><strong>Command Pattern:</strong> Encapsulate a request as an object, allowing parameterization, queuing, logging.</li> + <li><strong>Factory Pattern / Method:</strong> Create objects without specifying the exact class.</li> </ul> + <p>Understanding patterns helps write more maintainable, flexible, and reusable code. Frontend frameworks often implement patterns internally (e.g., Observer in reactivity, Command in state management actions).</p> </div> </div> </div> </div> <!-- /.row --> </div> <!-- /.schema-container --> - <!-- VIII. Key Considerations for Frontend Developers --> + <!-- VIII. Key Considerations for Frontend Developers & Architects --> <div class="schema-container section-arch" data-section-id="section-arch" data-section-name="Architecture"> <h2 class="section-title" id="section-arch-title">Key Considerations for Frontend Developers & Architects</h2> <div class="row"> <div class="col-12"> - <div class="info-card card-arch" id="card-arch-summary"> + <div class="info-card card-arch" id="card-arch-summary"> <!-- Updated --> <div class="card-body"> <h5 class="text-center"><i class="bi bi-building-gear" aria-hidden="true"></i> Architectural Decision Points</h5> <div class="card-content-wrapper"> - <p class="summary text-center">Key choices when building frontend applications: selecting <span class="term">frameworks/libraries</span>, defining <span class="term">state management</span> strategy, choosing <span class="term">build tools</span>, implementing <span class="term">testing</span>, managing <span class="term">performance</span>, ensuring <span class="term">compatibility</span> & <span class="term">accessibility</span>, and optimizing <span class="term">developer experience (DX)</span>. <a href="https://roadmap.sh/frontend" target="_blank" rel="noopener noreferrer" data-bs-toggle="tooltip" title="External link: Frontend Developer Roadmap">Frontend Roadmap</a></p> - <button class="btn btn-sm details-toggle mx-auto" type="button" data-bs-toggle="collapse" data-bs-target="#collapseArchConsiderations" aria-expanded="false" aria-controls="collapseArchConsiderations"> - Explore Further <i class="bi bi-chevron-down"></i> - </button> + <p class="summary text-center">Strategic choices impacting frontend application <span class="term">scalability, maintainability, performance, security,</span> and <span class="term">developer experience (DX)</span>. Includes framework selection, state/data management, build tooling, testing, rendering strategy. <a href="https://roadmap.sh/frontend" target="_blank">Frontend Roadmap</a></p> + <button class="btn btn-sm details-toggle mx-auto" type="button" data-bs-toggle="collapse" data-bs-target="#collapseArchConsiderations" aria-expanded="false" aria-controls="collapseArchConsiderations"> Explore Further <i class="bi bi-chevron-down"></i> </button> </div> </div> <div class="collapse collapse-content" id="collapseArchConsiderations"> - <h6>Core Considerations</h6> + <h6>Core Decision Areas</h6> <ul> - <li><strong>Framework/Library Choice:</strong> React, Vue, Angular, Svelte, or none? Based on team expertise, project scale, performance needs, ecosystem support, community.</li> - <li><strong>State Management:</strong> Local state, Context API, Redux, Zustand, Pinia, NgRx etc. Depends on application complexity, data flow patterns, and team preference.</li> - <li><strong>Build Tooling:</strong> Vite, Webpack, Parcel? Configuration complexity vs. build speed, dev server experience (HMR), plugin ecosystem.</li> - <li><strong>Testing Strategy:</strong> Levels of testing (unit, integration, component, E2E), chosen tools, target code coverage, testing pyramid/trophy.</li> - <li><strong>Performance Budget:</strong> Defining metrics (Core Web Vitals: LCP, FID/INP, CLS), bundle size limits, load times. Strategies for optimization.</li> - <li><strong>Cross-Browser/Device Compatibility:</strong> Target browsers/devices, testing approach, polyfills, progressive enhancement vs. graceful degradation.</li> - <li><strong>Accessibility (a11y):</strong> Integrating accessibility from the design phase through development and testing. Adherence to WCAG guidelines.</li> - <li><strong>SEO:</strong> Impact of rendering strategy (CSR, SSR, SSG, ISR). Frameworks like Next.js, Nuxt.js, SvelteKit often assist here.</li> - <li><strong>Developer Experience (DX):</strong> Tooling setup, HMR speed, linting/formatting, documentation, monorepo vs. polyrepo.</li> - <li><strong>TypeScript vs JavaScript:</strong> Trade-offs between static typing benefits (maintainability, early error detection) and potential development overhead/learning curve.</li> - <li><strong>Monorepo vs. Polyrepo:</strong> Code organization strategy for larger projects or multiple related applications/libraries.</li> - <li><strong>Data Fetching Strategy:</strong> REST, GraphQL, gRPC? Client-side fetching, server components, dedicated data fetching libraries (React Query, SWR).</li> + <li><strong>Framework/Library Choice:</strong> Assess React, Vue, Angular, Svelte, or others based on project complexity, team skills, performance needs, ecosystem maturity, community support, long-term maintenance goals.</li> + <li><strong>State Management Strategy:</strong> Evaluate scaling needs. Local state -> Context API / Composition API -> Zustand / Pinia -> Redux / NgRx. Consider complexity vs. benefits. Where does server state (data caching) fit (e.g., React Query, SWR)?</li> + <li><strong>Rendering Strategy (CSR/SSR/SSG/ISR):</strong> Balance SEO needs, initial load performance (TTFB/FCP/LCP), interactivity requirements (TTI/FID/INP), infrastructure complexity, content volatility. Leverage meta-frameworks (Next.js, Nuxt, SvelteKit, Astro).</li> + <li><strong>Component Architecture & Design Patterns:</strong> Atomic Design, Presentational/Container components, state colocation, hooks/composables for logic reuse. Establish clear conventions.</li> + <li><strong>Data Fetching Approach:</strong> REST, GraphQL, gRPC? Ad-hoc fetching vs. dedicated libraries (React Query, SWR, Apollo Client) for caching, synchronization, error handling. Where does data fetching happen (client, server component, API route)?</li> + <li><strong>Build Tooling & Configuration:</strong> Vite vs. Webpack vs. others. Balance DX (dev server speed, HMR) with build optimization capabilities and configuration complexity.</li> + <li><strong>Testing Strategy:</strong> Define testing pyramid/trophy balance (Unit, Integration, Component, E2E). Select appropriate tools. Establish coverage goals and CI integration.</li> + <li><strong>TypeScript vs JavaScript:</strong> Weigh benefits of static typing (safety, refactoring, tooling) against potential friction or learning curve for the team. Configure strictness appropriately.</li> + <li><strong>Monorepo vs. Polyrepo:</strong> Choose code organization strategy based on project/team size, shared code needs, deployment strategies. Tools like Nx, Turborepo can help manage monorepos.</li> + <li><strong>Styling Approach:</strong> CSS Modules, CSS-in-JS (Styled Components, Emotion), Utility-first (Tailwind CSS), component library styling (MUI, Bootstrap). Consider performance, DX, maintainability.</li> + <li><strong>Performance Budgeting:</strong> Set concrete goals for key metrics (Core Web Vitals, bundle sizes) and monitor them continuously.</li> + <li><strong>Accessibility (a11y) & Security:</strong> Integrate checks and best practices into the development workflow from the start, not as an afterthought.</li> + <li><strong>Deployment & Infrastructure:</strong> CI/CD pipelines, hosting platforms (Vercel, Netlify, Cloud providers), CDN strategy, environment management.</li> </ul> - <p>These decisions significantly impact maintainability, scalability, performance, security, and team productivity over the lifecycle of the application.</p> + <p><em>Architectural decisions involve trade-offs. Document choices and rationale. Revisit decisions as project evolves.</em></p> </div> </div> </div> @@ -1693,7 +2785,7 @@ function Controls() { <footer class="container text-center pb-3"> <p class="mb-1">© <span id="currentYear"></span> David Veksler Cheatsheets</p> - <p class="mb-2" style="font-size: 0.8em;">Last Updated: <span id="lastUpdatedDate">May 12, 2025</span></p> + <p class="mb-2" style="font-size: 0.8em;">Last Updated: <span id="lastUpdatedDate">May 12, 2025</span></p> <!-- Updated Date --> <div> <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript" title="External link: MDN JavaScript Guide" target="_blank" rel="noopener noreferrer" class="mx-2 link-secondary" data-bs-toggle="tooltip" data-bs-placement="top"> <i class="bi bi-book" aria-hidden="true"></i> MDN JS Docs @@ -1720,21 +2812,36 @@ function Controls() { </footer> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script> +<!-- Note: The script below contains the logic for interactivity (filters, search, lines, collapse) --> +<!-- It assumes Prism.js and Bootstrap JS are loaded before it executes. --> <script> document.addEventListener('DOMContentLoaded', () => { + // --- Initial Prism.js highlighting for visible code blocks --- + if (typeof Prism !== 'undefined') { + try { + Prism.highlightAll(); + } catch (e) { + console.warn("Prism.highlightAll() error on initial load:", e); + } + } + const mainContainer = document.getElementById('main-container'); const searchBox = document.getElementById('search-box'); const categoryFiltersContainer = document.getElementById('category-filters'); const noResultsDiv = document.getElementById('no-results'); const allSchemaContainers = Array.from(document.querySelectorAll('.schema-container')); - const allInfoCards = Array.from(document.querySelectorAll('.info-card')); + // const allInfoCards = Array.from(document.querySelectorAll('.info-card')); // Not directly used, cards are queried per section let currentHoverState = { card: null, line: null }; let activeFilter = 'all'; // To store the currently active category filter - // Initialize Bootstrap Tooltips - const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); - const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)); + // Initialize Bootstrap Tooltips (Defensive Check) + if (typeof bootstrap !== 'undefined' && typeof bootstrap.Tooltip === 'function') { + const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]'); + [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl)); + } else { + console.warn('Bootstrap Tooltip component not found. Static tooltips may not work or might throw errors if initialized later.'); + } // --- Initialize Filters & Search --- @@ -1749,7 +2856,10 @@ document.addEventListener('DOMContentLoaded', () => { allButton.setAttribute('data-bs-placement', 'top'); allButton.setAttribute('title', 'Show all categories'); categoryFiltersContainer.appendChild(allButton); - new bootstrap.Tooltip(allButton); + if (typeof bootstrap !== 'undefined' && typeof bootstrap.Tooltip === 'function') { // Dynamic tooltip init + new bootstrap.Tooltip(allButton); + } + const btnGroup = document.createElement('div'); btnGroup.classList.add('btn-group', 'flex-wrap'); @@ -1757,7 +2867,6 @@ document.addEventListener('DOMContentLoaded', () => { allSchemaContainers.forEach(section => { const sectionId = section.dataset.sectionId; - // Use data-section-name directly if available and accurate const sectionName = section.dataset.sectionName || section.querySelector('.section-title').textContent.trim().replace(' Features (ES6+)', '').replace(' Fundamentals', '').replace(' Environment & Web APIs','').replace(' & Libraries','').replace(' Patterns & Libraries','').replace(' Ecosystem & Tooling','').replace(' Concepts & Patterns','').replace(' Considerations for Frontend Developers & Architects',''); const button = document.createElement('button'); button.type = 'button'; @@ -1768,14 +2877,15 @@ document.addEventListener('DOMContentLoaded', () => { button.setAttribute('data-bs-placement', 'top'); button.setAttribute('title', `Filter by ${sectionName}`); btnGroup.appendChild(button); - new bootstrap.Tooltip(button); + if (typeof bootstrap !== 'undefined' && typeof bootstrap.Tooltip === 'function') { // Dynamic tooltip init + new bootstrap.Tooltip(button); + } }); categoryFiltersContainer.appendChild(btnGroup); // Event listener for search box searchBox.addEventListener('input', () => { applyFiltersAndSearch(); - // No line repositioning needed on search input usually, unless layout shifts drastically }); // Event listener for filter buttons (using event delegation) @@ -1794,7 +2904,7 @@ document.addEventListener('DOMContentLoaded', () => { function applyFiltersAndSearch() { const searchTerm = searchBox.value.toLowerCase().trim(); let itemsFound = 0; - let sectionsWithVisibleItems = 0; + // let sectionsWithVisibleItems = 0; // Not strictly needed for current logic allSchemaContainers.forEach(section => { const sectionId = section.dataset.sectionId; @@ -1806,14 +2916,12 @@ document.addEventListener('DOMContentLoaded', () => { const cardTitle = card.querySelector('h5') ? card.querySelector('h5').textContent.toLowerCase() : ''; const cardSummary = card.querySelector('p.summary') ? card.querySelector('p.summary').textContent.toLowerCase() : ''; const cardDetailsCollapse = card.querySelector('.collapse-content'); - // Include detail text only if it's not just a placeholder comment const cardDetailsText = (cardDetailsCollapse && !cardDetailsCollapse.textContent.includes('<!-- Detailed content needed -->') && !cardDetailsCollapse.textContent.includes('Content placeholder for')) ? cardDetailsCollapse.textContent.toLowerCase() : ''; const versionTag = card.querySelector('.version-tag') ? card.querySelector('.version-tag').textContent.toLowerCase() : ''; + const keywords = card.dataset.keywords ? card.dataset.keywords.toLowerCase() : ''; // Added keyword search - // Include data-keywords if you add them to cards - // const keywords = card.dataset.keywords ? card.dataset.keywords.toLowerCase() : ''; - const cardTextContent = `${cardTitle} ${cardSummary} ${cardDetailsText} ${versionTag}`; // Add keywords here if used + const cardTextContent = `${cardTitle} ${cardSummary} ${cardDetailsText} ${versionTag} ${keywords}`; // Include keywords const matchesSearch = searchTerm === '' || cardTextContent.includes(searchTerm); const matchesFilter = activeFilter === 'all' || sectionId === activeFilter; @@ -1822,36 +2930,45 @@ document.addEventListener('DOMContentLoaded', () => { if (matchesSearch && matchesFilter) { if(column) column.style.display = ''; // Show column - // card.style.display = 'flex'; // Card display is handled by column sectionHasVisibleCards = true; itemsFound++; } else { if(column) column.style.display = 'none'; // Hide column - // card.style.display = 'none'; } }); // Show/hide entire section based on filter and if it has visible cards if ((activeFilter === 'all' || sectionId === activeFilter) && sectionHasVisibleCards) { section.style.display = ''; - sectionsWithVisibleItems++; + // sectionsWithVisibleItems++; // Increment if tracking this } else if (searchTerm !== '' && (activeFilter === 'all' || sectionId === activeFilter) && !sectionHasVisibleCards) { // Section matches filter, but no cards match search, so hide section section.style.display = 'none'; - } - else if (activeFilter !== 'all' && sectionId !== activeFilter) { + } else if (activeFilter !== 'all' && sectionId !== activeFilter) { // Section does not match filter section.style.display = 'none'; } else if (searchTerm === '' && activeFilter === 'all') { - // No search, all filter, show if it has cards (already handled by sectionHasVisibleCards) + // No search, all filter, show/hide based only on whether it has cards section.style.display = sectionHasVisibleCards ? '' : 'none'; } else if (searchTerm === '' && sectionId === activeFilter) { - // No search, specific filter, show if it has cards (already handled) + // No search, specific filter, show/hide based only on whether it has cards section.style.display = sectionHasVisibleCards ? '' : 'none'; + } else { + // Default case: hide section if none of the above conditions met + section.style.display = 'none'; } }); noResultsDiv.style.display = itemsFound === 0 && (searchTerm !== '' || activeFilter !== 'all') ? 'block' : 'none'; + + // Re-highlight code blocks if Prism is loaded and items are visible + if (typeof Prism !== 'undefined' && (itemsFound > 0 || (searchTerm === '' && activeFilter === 'all'))) { + try { + Prism.highlightAll(); + } catch (e) { + console.warn("Prism.highlightAll() error during filter/search:", e); + } + } } @@ -1899,13 +3016,20 @@ document.addEventListener('DOMContentLoaded', () => { } function applyHoverState(card) { - if (!card || card === currentHoverState.card || card.style.display === 'none') return; + // Ensure card is visible before drawing line + const column = card.closest('.col-lg-4.col-md-6'); + if (!card || card === currentHoverState.card || (column && column.style.display === 'none')) return; - clearHoverState(true); + + clearHoverState(true); // Force clear previous before applying new const schemaContainer = card.closest('.schema-container'); - const sectionHeader = schemaContainer ? schemaContainer.querySelector('.section-title') : null; + // Ensure the container itself is visible too + if (!schemaContainer || schemaContainer.style.display === 'none') return; + + const sectionHeader = schemaContainer.querySelector('.section-title'); + // Check if LeaderLine is available const canDrawLine = sectionHeader && card.id && sectionHeader.id && sectionHeader.offsetParent !== null && card.offsetParent !== null && typeof LeaderLine !== 'undefined'; @@ -1916,7 +3040,7 @@ document.addEventListener('DOMContentLoaded', () => { if (canDrawLine) { try { const cardColor = getElementColor(card); - const line = new LeaderLine( + currentHoverState.line = new LeaderLine( // Assign to currentHoverState.line sectionHeader, card, { color: cardColor, size: 2.5, path: 'fluid', @@ -1925,10 +3049,9 @@ document.addEventListener('DOMContentLoaded', () => { dash: { animation: true, len: 8, gap: 4 }, } ); - currentHoverState.line = line; } catch (e) { console.error("LeaderLine error:", e); - clearHoverState(true); + clearHoverState(true); // Clear if line creation failed } } } @@ -1942,13 +3065,15 @@ document.addEventListener('DOMContentLoaded', () => { }); mainContainer.addEventListener('mouseout', (event) => { - const currentCard = currentHoverState.card; - if (currentCard && event.target.closest('.info-card') === currentCard) { - const relatedTarget = event.relatedTarget; + const currentCard = currentHoverState.card; // Card that had the line + if (currentCard && event.target.closest('.info-card') === currentCard) { // Mouse moved out of the card itself + const relatedTarget = event.relatedTarget; // Element mouse is moving to + // Clear if mouse moves out of the card and not into another part of the same card or a tooltip/line if (!currentCard.contains(relatedTarget) && (!relatedTarget || !relatedTarget.closest('.info-card'))) { - setTimeout(() => { - if (!currentCard.matches(':hover')) { - clearHoverState(false); + setTimeout(() => { // Delay to allow for re-entry or movement to related elements + // Double check if mouse isn't back over the card before clearing + if (currentHoverState.card && !currentHoverState.card.matches(':hover')) { // Only clear if mouse is *really* off the card + clearHoverState(false); // Not forcing, check if mouse is still over } }, 50); } @@ -1956,23 +3081,30 @@ document.addEventListener('DOMContentLoaded', () => { }); const positionLines = debounce(() => { - if (currentHoverState.line) { + if (currentHoverState.line && currentHoverState.card) { // Ensure card and line still exist try { - if (currentHoverState.line && typeof currentHoverState.line.position === 'function') { + if (typeof currentHoverState.line.position === 'function') { const startElem = currentHoverState.line.start; const endElem = currentHoverState.line.end; + const endElemColumn = endElem ? endElem.closest('.col-lg-4.col-md-6') : null; + + // Check if both elements are still in DOM, visible, and card's column is visible if (startElem && endElem && document.body.contains(startElem) && document.body.contains(endElem) && - startElem.offsetParent !== null && endElem.offsetParent !== null) { + startElem.offsetParent !== null && endElem.offsetParent !== null && + window.getComputedStyle(startElem).display !== 'none' && window.getComputedStyle(endElem).display !== 'none' && + endElemColumn && endElemColumn.style.display !== 'none' ) { currentHoverState.line.position(); } else { - clearHoverState(true); + // If elements are gone or hidden, remove the line and clear state + clearHoverState(true); // Force clear } } else { - clearHoverState(true); + // If line object is invalid for some reason + clearHoverState(true); // Force clear } } catch (e) { - console.warn("Reposition error:", e); - clearHoverState(true); + console.warn("LeaderLine reposition error:", e); + clearHoverState(true); // Force clear on error } } }, 100); @@ -1987,30 +3119,41 @@ document.addEventListener('DOMContentLoaded', () => { const iconEl = button ? button.querySelector('.bi') : null; if (button && iconEl) { - const updateIconState = () => { - if (collapseEl.classList.contains('show')) { + const updateIconStateAndHighlight = () => { + const isShown = collapseEl.classList.contains('show'); + if (isShown) { iconEl.classList.remove('bi-chevron-down'); iconEl.classList.add('bi-chevron-up'); button.setAttribute('aria-expanded', 'true'); + // Highlight code only when shown and Prism exists + if (typeof Prism !== 'undefined') { + try { + // Use highlightAllUnder for efficiency on specific section + Prism.highlightAllUnder(collapseEl); + } catch (e) { + console.warn("Prism.highlightAllUnder() error on collapse show:", e); + } + } } else { iconEl.classList.remove('bi-chevron-up'); iconEl.classList.add('bi-chevron-down'); button.setAttribute('aria-expanded', 'false'); } }; - updateIconState(); + updateIconStateAndHighlight(); // Initial state check - collapseEl.addEventListener('show.bs.collapse', () => { updateIconState(); setTimeout(positionLines, 50); }); - collapseEl.addEventListener('shown.bs.collapse', positionLines); - collapseEl.addEventListener('hide.bs.collapse', () => { updateIconState(); setTimeout(positionLines, 50); }); - collapseEl.addEventListener('hidden.bs.collapse', positionLines); + // Use bootstrap events for reliability + collapseEl.addEventListener('show.bs.collapse', () => { updateIconStateAndHighlight(); setTimeout(positionLines, 50); }); // Update icon immediately, reposition line slightly after animation starts + collapseEl.addEventListener('shown.bs.collapse', positionLines); // Reposition line fully after animation ends + collapseEl.addEventListener('hide.bs.collapse', () => { updateIconStateAndHighlight(); setTimeout(positionLines, 50); }); // Update icon immediately, reposition line slightly after animation starts + collapseEl.addEventListener('hidden.bs.collapse', positionLines); // Reposition line fully after animation ends } }); // --- Footer Year --- document.getElementById('currentYear').textContent = new Date().getFullYear(); - // --- Initial Setup --- + // --- Initial Setup Calls --- initializeFiltersAndSearch(); - applyFiltersAndSearch(); + applyFiltersAndSearch(); // Apply initial filter/search state (which also triggers Prism highlighting) }); </script> </body>