JavaScript Core Fundamentals

JS Overview

High-level, dynamically typed, single-threaded language with an event loop for non-blocking asynchronous operations. Primarily for web browsers & Node.js servers. MDN Intro

Purpose

Adds interactivity to web pages, builds full-stack web/mobile apps, powers servers (Node.js), automation, and more.

Key Characteristics
  • Dynamic Typing: Variable types determined at runtime. Offers flexibility but requires careful handling.
  • Interpreted/JIT-Compiled: Modern engines (V8, SpiderMonkey) use Just-In-Time compilation for performance.
  • Event Loop: Core mechanism enabling non-blocking I/O by offloading operations and processing results via a callback queue. Event Loop Explained
  • Prototype-based Inheritance: Objects inherit directly from other objects (prototypes). ES6 Classes provide syntax sugar.
  • Multi-paradigm: Supports procedural, object-oriented (via prototypes/classes), and functional programming styles.
Variables & Scope

Declare using let (reassignable, block-scoped), const (constant reference, block-scoped), or legacy var (function-scoped, hoisted). MDN Declarations

Declarations
  • const: Block-scoped (`{}`). Must be initialized. Cannot be reassigned. Use when the variable reference shouldn't change. (Note: Object/array *contents* can still be mutated).
  • let: Block-scoped (`{}`). Can be reassigned. Can be declared without initialization (`undefined` by default). Use for variables that need to change value.
  • var: Function-scoped (or global). Subject to hoisting issues (declaration moved up, initialization stays). Generally avoid in modern ES6+ code.
Scope
  • Block Scope: Variables (`let`/`const`) only accessible within the `{...}` block (e.g., `if`, `for`, `while`) where defined.
  • Function Scope: Variables (`var`) accessible anywhere within the function they are defined in, regardless of blocks.
  • Global Scope: Variables declared outside any function/block. Accessible everywhere (avoid polluting global scope).
  • Lexical Scope: Inner functions have access to variables of their outer functions (forms closures).
Hoisting & Temporal Dead Zone (TDZ)

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`. Hoisting | TDZ

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
}
scopeTest();
// console.log(varVar); // ReferenceError: varVar is not defined (outside function scope)
Data Types

JS has 7 primitive types (immutable) and the Object type (mutable). Use `typeof` for basic checks. Beware type coercion; prefer strict equality (`===`). MDN Data Structures

Primitives (Immutable)
  • string: Textual data (e.g., `"hello"`, `'world'`, `` `template` ``).
  • number: Numeric values (e.g., `42`, `3.14`, `1e6`). Includes special values `Infinity`, `-Infinity`, `NaN` (Not-a-Number).
  • boolean: Logical values (`true`, `false`).
  • null: Intentional absence of any object value. Represents "no value".
  • undefined: Variable declared but not yet assigned a value; also default function return value.
  • symbol (ES6): Unique, immutable identifier, often used as non-string object property keys. `Symbol('desc')`.
  • bigint (ES2020): Arbitrary precision integers (e.g., `9007199254740991n`). For numbers larger than `Number.MAX_SAFE_INTEGER`.
Object (Mutable)
  • object: Collection of properties (key-value pairs). Includes arrays, functions, Date, RegExp, Map, Set, etc. Passed by reference.
Type Checking (`typeof`)
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"
Type Coercion & Equality

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. Equality Comparisons

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)
Operators

Symbols performing operations on values (operands). Includes arithmetic (`+`, `-`, `*`, `/`, `%`), comparison (`>`, `<`, `===`, `!==`), logical (`&&`, `||`, `!`), assignment (`=`, `+=`), and others. MDN Operators

Common Operator Types
  • Arithmetic: `+` (addition/concatenation), `-` (subtraction), `*` (multiplication), `/` (division), `%` (remainder/modulo), `**` (exponentiation ES7), `++` (increment), `--` (decrement).
  • Assignment: `=` (assign), `+=`, `-=`, `*=`, `/=`, `%=` (compound assignment).
  • Comparison: `==` (loose equality), `!=` (loose inequality), `===` (strict equality), `!==` (strict inequality), `>`, `>=`, `<`, `<=`.
  • Logical: `&&` (AND), `||` (OR), `!` (NOT). Short-circuiting behavior is important.
  • Bitwise: `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>` (Less common in frontend).
  • String: `+` (concatenation).
  • Conditional (Ternary): `condition ? valueIfTrue : valueIfFalse`.
  • Type: `typeof` (returns string indicating type), `instanceof` (checks if object is instance of a class/constructor).
  • Comma: `,` (Evaluates multiple expressions, returns the last one).
  • Spread/Rest (`...`): Used in arrays, objects, function calls/definitions (See Modern JS).
  • Optional Chaining (`?.`): Access nested properties safely (See Modern JS).
  • Nullish Coalescing (`??`): Provide default for `null` or `undefined` (See Modern JS).

Operator precedence determines the order of evaluation. Use parentheses `()` to enforce specific order. Operator Precedence

Control Flow

Directs the order of execution. Conditionals (`if/else`, `switch`) branch execution. Loops (`for`, `while`, `do...while`, `for...of`, `for...in`) repeat execution. MDN Control Flow

Conditionals
  • `if...else if...else`: Execute blocks based on conditions.
  • `switch`: Efficiently compare one value against multiple `case` values. Use `break` to exit.
Loops
  • `for` loop: `for (initialization; condition; final-expression) { ... }` - Standard loop for known iteration counts.
  • `while` loop: `while (condition) { ... }` - Loop while condition is true. Condition checked *before* execution.
  • `do...while` loop: `do { ... } while (condition);` - Loop while condition is true. Condition checked *after* execution (always runs at least once).
  • `for...in` loop: `for (const key in object) { ... }` - Iterates over enumerable property *keys* (usually strings) of an object. Avoid for arrays.
  • `for...of` loop (ES6): `for (const value of iterable) { ... }` - Iterates over the *values* of iterable objects (Arrays, Strings, Maps, Sets). Preferred way to loop over array values.
Other Control Statements
  • `break`: Exits the current loop or switch statement.
  • `continue`: Skips the rest of the current loop iteration and proceeds to the next.
  • `try...catch...finally`: Handles errors (exceptions). `try` block contains code that might throw, `catch` handles the error, `finally` always executes (optional). try...catch
// 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
  }
}
Functions

Reusable code blocks. Defined as declarations or expressions. Understand scope, closures, `this` binding, parameters (default/rest). First-class citizens. MDN Functions

Defining Functions
  • Declaration: `function name(...) { ... }` (Hoisted).
  • Expression: `const name = function(...) { ... };` (Variable hoisted, function not).
  • Arrow Function (ES6): `const name = (...) => { ... };` (Concise, lexical `this`).
  • Named Function Expression: `const name = function innerName(...) { ... };` (Name available inside).
  • Immediately Invoked Function Expression (IIFE): `(function() { ... })();` (Creates private scope, less common with modules).
Closures

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. MDN Closures

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)
`this` Keyword Binding

The value of `this` depends on *how* the function is called: MDN `this`

  • Global Context: `window` (browser, non-strict mode) or `undefined` (strict mode).
  • Method Invocation: `object.method()` sets `this` to `object`.
  • Constructor Invocation: `new MyClass()` sets `this` to the newly created instance inside the constructor.
  • Explicit Binding: `func.call(thisArg, ...args)`, `func.apply(thisArg, [argsArray])`, `func.bind(thisArg)` (returns new function with fixed `this`).
  • Arrow Functions: Inherit `this` lexically from the surrounding scope where they are defined. They do *not* have their own `this` binding.
Parameters
  • Default Parameters (ES6): `function greet(name = 'Guest') { ... }`
  • Rest Parameters (ES6): `function sum(...numbers) { ... }` (collects arguments into an array).
  • `arguments` object: (Legacy, avoid in ES6+) Array-like object containing all passed arguments (not available in arrow functions).
Arrays

Ordered lists of values (any type). Zero-indexed. Rich method set for iteration (`map`, `filter`, `reduce`), mutation (`push`, `splice`), etc. Use spread (`...`). MDN Array

Creating & Accessing
const empty = [];
const items = [1, 'two', { three: 3 }, [4]];
console.log(items[1]); // 'two'
console.log(items.length); // 4
Common Iteration Methods
  • `forEach(callback(value, index, array))`: Executes callback for each element.
  • `map(callback(value, index, array))`: Creates a *new* array with results of calling callback on every element.
  • `filter(callback(value, index, array))`: Creates a *new* array with elements that pass the callback's test (return true).
  • `reduce(callback(accumulator, currentValue, index, array), initialValue?)`: Executes callback on each element, resulting in a single output value (the accumulator).
  • `find(callback(value, index, array))`: Returns the *first* element that passes the test.
  • `findIndex(callback(value, index, array))`: Returns the *index* of the first element that passes the test.
  • `some(callback(value, index, array))`: Checks if *at least one* element passes the test.
  • `every(callback(value, index, array))`: Checks if *all* elements pass the test.
Mutation Methods
  • `push(item1, ...)` / `pop()`: Add/remove from end.
  • `unshift(item1, ...)` / `shift()`: Add/remove from beginning.
  • `splice(start, deleteCount?, item1?, ...)`: Remove/replace elements.
  • `sort(compareFn?)` / `reverse()`: Sort/reverse in place.
Other Useful Methods
  • `slice(start?, end?)`: Returns a shallow copy of a portion.
  • `concat(arr1, ...)`: Returns a new array merging arrays.
  • `includes(value, fromIndex?)`: Checks if value exists.
  • `indexOf(value, fromIndex?)` / `lastIndexOf()`: Find index of value.
  • `join(separator?)`: Join elements into a string.
  • `Array.isArray(value)`: Check if value is an array.
// 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
Objects & Prototypes

Unordered collections of key-value pairs. JS uses prototypal inheritance. Access properties via dot (`.`) or bracket (`[]`) notation. MDN Objects

Creating & Accessing
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
Object Methods
  • `Object.keys(obj)`: Returns array of own property keys.
  • `Object.values(obj)`: Returns array of own property values.
  • `Object.entries(obj)`: Returns array of `[key, value]` pairs.
  • `Object.assign(target, ...sources)`: Copies properties from sources to target (shallow copy).
  • `Object.create(proto, propertiesObject?)`: Creates a new object with the specified prototype object and properties.
  • `Object.hasOwn(obj, prop)` (ES2022) / `obj.hasOwnProperty(prop)` (older): Checks if object has own property (not inherited).
  • `Object.freeze(obj)`: Prevents modifications (shallow).
Prototypal Inheritance

Objects inherit properties from their prototype (`[[Prototype]]`). Lookups follow the prototype chain until the property is found or the chain ends (`null`). Prototype Chain

// 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();

Modern JavaScript Features (ES6+)

Arrow Functions ES6+

Concise syntax for functions. Lexically binds `this` (inherits from surrounding scope). No `arguments` object. Not suitable for methods needing own `this` or constructors. MDN Arrow Functions

Syntax Examples
// 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 });
Lexical `this`

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.

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();
Limitations
  • Cannot be used as constructors (`new` throws error).
  • Do not have their own `arguments` object (use rest parameters `...args` instead).
  • Not suitable for object methods that rely on dynamic `this` binding (use regular function syntax instead).
  • No `prototype` property.
Classes ES6+

Syntactic sugar over prototypal inheritance. Provides `class`, `constructor`, `extends`, `super`, static methods, getters/setters for cleaner object creation and inheritance. MDN Classes

Defining Classes & Inheritance
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.'); }
}

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}`);
  }
}

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)
Key Features
  • `constructor` method: Initializes object instance. Only one per class.
  • `extends` keyword: Sets up prototype chain for inheritance.
  • `super` keyword: Calls parent class constructor (`super()`) or methods (`super.methodName()`).
  • Static methods/properties: Belong to the class itself, not instances. Accessed via `ClassName.staticMember`.
  • Getters & Setters: Define computed properties using `get propName()` and `set propName(value)`.
  • Public/Private Fields (Experimental): `#field` syntax for private instance fields (check browser/Node support).

Classes are still based on prototypes; they don't change the underlying inheritance model.

Modules (ESM) ES6+

Standard JS module system. Use `import` / `export` (named or default) for code organization, reusability, and dependency management. Statically analyzed. MDN Modules

Exporting (from `utils.js`)
// 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; }
}
Importing (into `main.js`)
// 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
Usage & Characteristics
  • Static Structure: Imports/exports must be top-level (cannot be conditional). Allows build tools to analyze dependencies.
  • Strict Mode: Modules always execute in strict mode.
  • Scope: Each module has its own top-level scope.
  • Browsers: Use `<script type="module" src="main.js">`.
  • Node.js: Use `.mjs` extension or `"type": "module"` in `package.json`. Interoperability with CommonJS (`require`) exists but has nuances.
  • Dynamic `import()`: Function-like `import('./module.js')` returns a Promise, allowing conditional/lazy loading of modules.
Promises ES6+

Represents eventual result (or failure) of an async operation. Enables cleaner async code via chaining (`.then`, `.catch`, `.finally`). Foundation for `async/await`. MDN Promise

States & Flow
  • Pending: Initial state. Operation not yet completed.
  • Fulfilled: Operation completed successfully, resolves with a value.
  • Rejected: Operation failed, rejects with an error/reason.

Promises are immutable once settled (fulfilled or rejected).

Creating Promises (Less common now with `async/await` and Promise-based APIs)
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
    }
  }, 1000);
});
Consuming Promises
myPromise
  .then(result => { // Handles fulfillment
    console.log("Success:", result);
    return "Processed: " + result; // Value passed to next .then
  })
  .then(processedResult => {
      console.log("Next step:", processedResult);
  })
  .catch(error => { // Handles rejection from promise or any previous .then
    console.error("Error:", error.message);
  })
  .finally(() => { // Executes regardless of success or failure
    console.log("Promise settled.");
  });
Common Static Methods
  • `Promise.all(iterable)`: Waits for all promises to fulfill. Rejects immediately if *any* reject. Useful for parallel independent operations.
  • `Promise.race(iterable)`: Settles as soon as the *first* promise in the iterable settles (fulfills or rejects).
  • `Promise.allSettled(iterable)`: 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.
  • `Promise.any(iterable)` (ES2021): Waits for the *first* promise to fulfill. Rejects only if *all* promises reject.
  • `Promise.resolve(value)` / `Promise.reject(reason)`: Create already settled promises.
Async/Await ES2017+

Syntactic sugar over Promises. Write asynchronous code that looks synchronous. `async` functions return Promises. `await` pauses execution until a Promise settles. MDN Async Function

Usage
  • `async` Keyword: 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.
  • `await` Keyword: *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`).
Example (Fetch with Async/Await)
async function getUserData(userId) {
  console.log(`Fetching data for user ${userId}...`);
  try {
    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(); // Pause until json() promise settles
    console.log('Data received:', data);
    return data; // This value fulfills the promise returned by getUserData
  } catch (error) {
    console.error('Fetch failed:', error);
    // Handle error or re-throw to reject the promise returned by getUserData
    throw error;
  }
}

// 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();
Parallel Operations with `await`

Use `Promise.all()` with `await` to wait for multiple promises concurrently.

async function fetchMultiple() {
  try {
    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();
Destructuring ES6+

Unpack values from arrays or properties from objects into variables. Cleaner syntax for accessing data and function parameters. MDN Destructuring

Array Destructuring
const scores = [100, 85, 92, 78];

// Basic assignment
const [first, second] = scores; // first=100, second=85

// 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
Object Destructuring
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 }
Function Parameters

Very common for unpacking options objects or props in frameworks.

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])
Template Literals ES6+

Enhanced string literals using backticks (`` ` ``). Allow embedded expressions (`${expression}`), multiline strings, and tagged templates. MDN Template Literals

String Interpolation

Embed expressions directly within the string.

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!)
Multiline Strings

Newlines within backticks are preserved in the string.

const html = `

Title

Paragraph text.

`; console.log(html);
Tagged Templates

Advanced feature where a function (the "tag") processes the template literal parts. Used by libraries like styled-components.

function highlight(strings, ...values) {
  let result = '';
  strings.forEach((str, i) => {
    result += str;
    if (values[i]) {
      result += `${values[i]}`;
    }
  });
  return result;
}

const term = "JavaScript";
const info = "awesome";
const tagged = highlight`Learn ${term}, it's ${info}!`;
console.log(tagged); // Learn JavaScript, it's awesome!
Opt. Chaining & Nullish Coalescing ES2020+

Safely access nested properties with Optional Chaining (`?.`). Provide defaults for `null` or `undefined` with Nullish Coalescing (`??`). `?.` | `??`

Optional Chaining (`?.`)

Stops evaluation and returns `undefined` if the value before `?.` is `null` or `undefined`, preventing errors when accessing properties of potentially non-existent objects.

const user = {
  name: 'Charlie',
  // address: { street: '123 Main St' } // address might be missing
};

// Without optional chaining (throws error if address is missing)
// const street = user.address.street;

// With optional chaining
const street = user.address?.street; // undefined if user.address is null/undefined
console.log(street);

// Works with function/method calls too
const adminName = user.adminProfile?.getName?.(); // undefined if adminProfile or getName missing
Nullish Coalescing Operator (`??`)

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).

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}`);
Map & Set ES6+

Map holds key-value pairs (any type as key). Set stores unique values (any type). Both iterable. Better alternatives to objects/arrays for certain use cases. Map | Set

Map
  • Ordered key-value pairs. Keys can be any type (objects, functions, etc.).
  • Methods: `set(key, value)`, `get(key)`, `has(key)`, `delete(key)`, `clear()`, `size`.
  • Iterable: `keys()`, `values()`, `entries()`, `forEach()`.
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); }
Set
  • Collection of unique values. Order based on insertion.
  • Methods: `add(value)`, `has(value)`, `delete(value)`, `clear()`, `size`.
  • Iterable: `values()`, `keys()` (alias for values), `entries()` (`[value, value]`), `forEach()`.
const uniqueNums = new Set([1, 2, 3, 2, 1]);
uniqueNums.add(4);
uniqueNums.add(1); // Ignored, already exists

console.log(uniqueNums.has(2)); // true
console.log(uniqueNums.size); // 4
for (const num of uniqueNums) { console.log(num); } // 1, 2, 3, 4

// Common use case: Remove duplicates from array
const numbers = [5, 6, 5, 7, 6];
const unique = [...new Set(numbers)]; // [5, 6, 7]

Browser Environment & Web APIs

The DOM

Document Object Model: API for HTML/XML documents. Represents structure as a node tree. JS interacts via `document` object to manipulate content/style. MDN DOM Intro

Key Concepts
  • Node Tree: Represents document structure (elements, text, attributes, comments).
  • `document` Object: Root entry point (`document.body`, `document.head`, `document.documentElement`).
  • Node Types: `Element`, `Text`, `Attribute`, `Comment`, `Document`, etc.
  • Traversal: Navigating the tree (`parentNode`, `childNodes`, `firstChild`, `lastChild`, `nextSibling`, `previousSibling`).
  • Live vs. Static Collections: `getElementsByTagName`/`ClassName` return live `HTMLCollection`s (update automatically). `querySelectorAll` returns a static `NodeList`.

Modern frameworks (React, Vue, etc.) abstract direct DOM manipulation but understanding it is crucial.

DOM Manipulation

Selecting elements (`querySelector`), modifying content/attributes/styles, creating/adding/removing elements (`createElement`, `appendChild`, `remove`). MDN Manipulating Docs

Common Tasks & Methods
  • Selecting:
    • `document.getElementById('id')`
    • `document.querySelector(cssSelector)` (first match)
    • `document.querySelectorAll(cssSelector)` (static NodeList)
    • `element.closest(cssSelector)` (finds nearest ancestor)
  • Modifying Text/HTML: `element.textContent` (safer), `element.innerHTML` (parses HTML, potential XSS).
  • Attributes: `element.setAttribute()`, `element.getAttribute()`, `element.removeAttribute()`, `element.hasAttribute()`, `element.dataset` (for `data-*` attributes).
  • Classes: `element.classList.add()`, `.remove()`, `.toggle()`, `.contains()`.
  • Styles: `element.style.propertyName = 'value'` (sets inline styles, `propertyName` is camelCase e.g., `backgroundColor`).
  • Creating: `document.createElement('tag')`, `document.createTextNode('text')`.
  • Adding/Inserting: `parent.appendChild(child)`, `parent.insertBefore(new, ref)`, `element.append(...nodes)`, `element.prepend(...nodes)`, `element.before(...nodes)`, `element.after(...nodes)`.
  • Removing: `element.remove()`.
  • Dimensions/Position: `element.getBoundingClientRect()`, `element.offsetWidth`, `offsetHeight`.

Direct manipulation is less common with frameworks but essential for vanilla JS or specific integration tasks.

Event Handling

Respond to user interactions or browser events. Use `addEventListener`. Understand event object, bubbling/capturing, `preventDefault`, `stopPropagation`. MDN Events

Attaching Listeners

Prefer `addEventListener` over `on` attributes/properties.

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);
Event Object Properties

`type`, `target`, `currentTarget`, `bubbles`, `cancelable`, `timeStamp`, mouse coords (`clientX`, `clientY`, `pageX`, `pageY`), key info (`key`, `code`, `keyCode`), etc.

Event Phases & Delegation
  • Capturing Phase: Down the tree (window -> target).
  • Target Phase: At the element.
  • Bubbling Phase: Up the tree (target -> window). Default.
  • Event Delegation: Attach listener to a parent. Check `event.target` to identify which child triggered the event. Efficient for many child elements or dynamic content.
Common Event Types

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`).

Fetch API

Modern interface for network requests (HTTP). Promise-based. Replaces older `XMLHttpRequest`. Handles Request/Response objects. MDN Using Fetch

Basic GET Request (Async/Await)
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}`);
    }
    const users = await response.json(); // Parses JSON body
    console.log(users);
    return users;
  } catch (error) {
    console.error('Failed to fetch users:', error);
  }
}
POST Request with Options
async function createUser(userData) {
  try {
    const response = await fetch('https://api.example.com/users', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        // 'Accept': 'application/json',
        // 'Authorization': 'Bearer YOUR_TOKEN'
      },
      body: JSON.stringify(userData)
    });
    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('Failed to create user:', error);
  }
}
createUser({ name: 'Jane Doe', job: 'Architect' });
Response Object

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.

Request Object & Options

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).

Error Handling

`fetch` only rejects on *network errors*. HTTP error statuses (like 404, 500) do *not* cause rejection; check `response.ok` manually.

Web Storage

APIs for storing key-value pairs locally in the browser. `localStorage` persists after browser close. `sessionStorage` clears when session ends. Synchronous API. MDN Web Storage

API Methods (Same for both)
  • `setItem(key, value)`: Store data (value is always stored as string).
  • `getItem(key)`: Retrieve data (returns string or `null`).
  • `removeItem(key)`: Delete item by key.
  • `clear()`: Remove all items.
  • `key(index)`: Get key name by index.
  • `length`: Number of items stored.
// 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
Differences & Considerations
  • Persistence: `localStorage` persists until explicitly cleared. `sessionStorage` tied to browser tab/window session.
  • Scope: Both scoped to the origin (protocol, host, port).
  • Capacity: Typically 5-10MB per origin (browser dependent).
  • Synchronous: Operations block the main thread (can impact performance if used heavily).
  • Data Type: Stores only strings. Use `JSON.stringify()` and `JSON.parse()` for objects/arrays.
  • Alternatives: IndexedDB (async, larger storage, complex), Cookies (sent with HTTP requests, smaller).
Timers & Animation

Schedule code execution. `setTimeout` runs once after delay. `setInterval` runs repeatedly. `requestAnimationFrame` for smooth animations synchronized with display refresh. Timers | rAF

`setTimeout` & `clearTimeout`

Executes a function or code snippet once after a specified delay (in milliseconds).

const timeoutId = setTimeout(() => {
  console.log('This runs after 2 seconds.');
}, 2000);

// To cancel before it runs:
// clearTimeout(timeoutId);
`setInterval` & `clearInterval`

Repeatedly executes a function or code snippet, with a fixed time delay between each call.

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);
`requestAnimationFrame` (rAF)

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.

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

Use `cancelAnimationFrame()` to stop an rAF loop.

Browser Object Model (BOM)

Browser-specific APIs beyond the DOM standard. Includes the global `window` object, `navigator` (browser info), `location` (URL), `history` (navigation). MDN Window

`window` Object
  • The global object in browser context.
  • Provides access to DOM (`window.document`), BOM, timers, console, etc.
  • Properties like `innerWidth`, `innerHeight`, `screenX`, `screenY`.
  • Methods like `alert()`, `prompt()`, `confirm()`, `open()`, `close()`, `scroll()`.
`navigator` Object
  • Information about the browser: `userAgent`, `language`, `platform`, `onLine`.
  • Access to features like Geolocation (`navigator.geolocation`), Clipboard API (`navigator.clipboard`), Permissions API (`navigator.permissions`).
`location` Object
  • Information about the current URL: `href`, `protocol`, `host`, `hostname`, `port`, `pathname`, `search`, `hash`.
  • Methods for navigation: `assign(url)`, `replace(url)`, `reload()`.
`history` Object
  • Manages session history.
  • Methods: `back()`, `forward()`, `go(delta)`.
  • `pushState()` and `replaceState()` allow manipulating history state without full page loads (used by SPA routers).

Frontend Frameworks & Libraries

React Overview

Library for building UIs via Virtual DOM and components. Declarative, uses JSX and Hooks for state/lifecycle in functional components. React Docs

Key Concepts
  • Declarative UI: Describe *what* the UI should look like based on state, React handles DOM updates.
  • Component-Based: Build encapsulated components that manage their own state, compose them to make complex UIs.
  • Virtual DOM: In-memory representation of UI. React calculates minimal DOM changes ("diffing") for efficient updates.
  • JSX: Syntax extension, looks like HTML but is compiled to JS function calls (`React.createElement`).
  • Props: Pass data down from parent to child (read-only).
  • State: Data managed within a component that changes over time, triggering re-renders.
  • Hooks: Functions (e.g., `useState`, `useEffect`) enabling state and lifecycle features in functional components.
  • Unidirectional Data Flow: State flows down (parent to child via props), events flow up (child to parent via callbacks).
JSX

JavaScript XML: HTML-like syntax in JS. Embed expressions `{}`. Use `className`, `htmlFor`. Transpiled to `React.createElement()`. React JSX Intro

Key Features & Syntax
  • Embedding Expressions: Use curly braces `{}` for any valid JS expression (variables, function calls, ternary operators). E.g., `

    {user.name}

    `, `

    Total: {price * quantity}

    `.
  • Attributes: Use camelCase for most HTML attributes (`className`, `tabIndex`, `onClick`, `htmlFor`). Standard HTML attributes (`data-*`, `aria-*`) remain lowercase.
  • Boolean Attributes: `{isEnabled}` is shorthand for `isEnabled={true}`. Omitting means `false`.
  • Style Attribute: Takes a JS object with camelCased CSS properties: `style={{ color: 'red', backgroundColor: '#eee' }}`.
  • Root Element: Components must return a single root element. Use Fragments (`<>...` or `...`) to avoid extra divs.
  • Self-Closing Tags: Required for elements without children (``, `
    `).
  • Comments: Use JS block comments within braces: `{/* Comment here */}`.
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>
  );
}
Components (React)

Reusable UI building blocks. Typically functions returning JSX. Receive data via props (read-only). Manage internal data with state (Hooks). React Components

Functional Components (Standard)

Plain JavaScript functions that accept `props` as an argument and return React elements (usually 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>
  );
}
Props (Properties)
  • Data passed down from parent components.
  • Read-only within the child component (unidirectional data flow).
  • Accessed via the `props` object (e.g., `props.userName`) or by destructuring (`function Welcome({ name }) { ... }`).
Composition

Components can render other components, allowing complex UIs to be built from smaller, reusable pieces.

function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Counter />
    </div>
  );
}
Class Components (Legacy)

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.

State & Lifecycle (Hooks) React 16.8+

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. React Hooks Reference

Core Hooks
  • `useState(initialState)`: Declares state variable. Returns `[stateValue, setStateFunction]`. Trigger re-render on state change.
  • `useEffect(setupFn, dependencies?)`: 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).
  • `useContext(Context)`: Reads value from nearest `Context.Provider` above it in the tree. Re-renders when context value changes.
Additional Common Hooks
  • `useReducer(reducer, initialArg, init?)`: Alternative to `useState` for complex state logic involving multiple sub-values or when next state depends on previous one.
  • `useCallback(fn, dependencies)`: Returns a memoized version of the callback function that only changes if dependencies change. Useful for optimizing child components relying on reference equality.
  • `useMemo(computeFn, dependencies)`: Returns a memoized value. Runs `computeFn` only when dependencies change. Useful for expensive calculations.
  • `useRef(initialValue)`: 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.
  • `useLayoutEffect(setupFn, dependencies?)`: 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.

See individual Hook cards or React docs for detailed examples.

Handling Events (React)

Use camelCase event names (`onClick`, `onChange`). Pass event handler functions (often defined inline or as component methods). React uses a SyntheticEvent system. React Events

Syntax
function MyButton() {
  function handleClick(event) {
    console.log('Button clicked!', event); // event is SyntheticEvent
    // event.preventDefault(); // Can still prevent default
  }

  function handleChange(event) {
      console.log('Input value:', event.target.value);
  }

  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>
    </>
  );
}
SyntheticEvent
  • React wraps the browser's native event in a `SyntheticEvent` object.
  • Provides a cross-browser consistent API (e.g., `event.preventDefault()`, `event.stopPropagation()`).
  • Access the native event via `event.nativeEvent`.
  • 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.
Passing Handlers as Props

Often, child components receive handlers from parents via props to communicate events upwards.

function ChildButton({ onCustomClick }) { // Receives handler via prop
  return <button onClick={onCustomClick}>Click Child</button>;
}

function Parent() {
  function handleChildClick() {
    console.log('Child button was clicked!');
  }
  return <ChildButton onCustomClick={handleChildClick} />;
}
Conditional Rendering

Render different UI based on conditions. Use standard JS: `if`/`else`, ternary operator (`condition ? ... : ...`), logical AND (`&&`), or `null` return. React Conditional Rendering

Common Patterns
  • `if/else` (outside JSX): Prepare content in variables before returning JSX.
  • Ternary Operator (`condition ? exprIfTrue : exprIfFalse`): Inline conditional expression.
  • Logical AND (`condition && expression`): Renders `expression` only if `condition` is truthy. If `condition` is falsy, renders `false` (which React ignores).
  • Returning `null`: A component returning `null` renders nothing.
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>; }
Lists & Keys

Render collections of items using array methods like `.map()`. Each list item needs a unique, stable `key` prop for efficient updates. React Rendering Lists

Rendering with `.map()`
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>;
}
The `key` Prop
  • Helps React identify which items have changed, are added, or are removed.
  • Keys should be **unique** among siblings in the list.
  • Keys should be **stable** (not change between renders for the same item).
  • Usually use item IDs from your data (`item.id`).
  • **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.
Extracting List Item Components

For more complex list items, extract them into their own component. The `key` still needs to be on the element returned by `.map`.

function TodoItem({ todo }) { // Receives single todo item
  return <li>{todo.text}</li>;
}

function TodoList({ todos }) {
  return (
    <ul>
      {todos.map(todo =>
        // Key goes here on the component instance
        <TodoItem key={todo.id} todo={todo} />
      )}
    </ul>
  );
}
Vue.js Overview

Progressive framework focused on approachability. Uses HTML-based templates, reactive data, and component composition. Supports Options & Composition API. Vue Docs

Key Concepts
  • Templates: HTML-based syntax binding DOM to component data using directives (`v-bind`, `v-on`, `v-model`, `v-if`, `v-for`).
  • Reactivity: Core system automatically tracks dependencies and updates DOM when state changes.
  • Components: Often Single File Components (`.vue`) encapsulating template, script (`<script setup>` for Composition API), and style.
  • Options API: Traditional way using `data()`, `methods`, `computed`, `watch`, lifecycle hooks options.
  • Composition API (Vue 3+): Organize logic by feature using functions like `ref()`, `reactive()`, `computed()`, `watch()`, `onMounted()`. More flexible for large components and logic reuse.

More detail on template syntax, directives, and API differences needed.

Angular Overview

Comprehensive platform for building large-scale apps using TypeScript. Features components, modules, DI, routing, RxJS integration, CLI tooling. Opinionated. Angular Docs

Key Concepts
  • TypeScript: Core language, enabling strong typing and OOP features.
  • Components: Combine HTML template, CSS styles, and TypeScript class logic (`@Component` decorator).
  • Templates: Enhanced HTML with data binding (`[]`, `()`, `[()]`) and directives (`*ngIf`, `*ngFor`).
  • Modules (NgModules): Organize application parts, declare components/directives/pipes, manage dependencies (`@NgModule` decorator). Standalone Components becoming more common.
  • Dependency Injection (DI): Built-in hierarchical injector provides services and dependencies.
  • Services: Classes (`@Injectable`) for reusable logic, data access.
  • Routing: Powerful module (`RouterModule`) for client-side navigation.
  • RxJS: Extensively used for handling asynchronous events and data streams (Observables).
  • Angular CLI: Essential tool for project scaffolding, generation, building, testing, deployment.

More detail on decorators, data binding syntax, directives, pipes, and RxJS needed.

Svelte Overview

A compiler that turns declarative component code into efficient imperative JavaScript. No Virtual DOM. Truly reactive via assignments. Minimal runtime. Svelte Docs

Key Concepts
  • Compiler Approach: Shifts work to build time, resulting in smaller bundles and faster runtime performance.
  • No Virtual DOM: Generates highly optimized imperative code to update the DOM directly when state changes.
  • Reactivity: Variable assignments (`count = 1`, `user.name = 'X'`) automatically trigger updates where those variables are used. Use `$: ` for reactive declarations/statements.
  • Single File Components (`.svelte`): Combine `<script>`, template (HTML-like), and `<style>` (scoped by default).
  • Stores: Built-in system (`writable`, `readable`, `derived`) for managing state outside components and sharing it reactively.
  • Transitions & Animations: First-class directives (`transition:`, `animate:`, `in:`, `out:`) for smooth UI effects.
  • Context API: Similar to React/Vue for avoiding prop drilling (`setContext`, `getContext`).

More detail on template syntax (logic blocks, event handling), reactive declarations, stores needed.

State Management Patterns & Libraries

State Management Concepts

Handling data that changes over time. Distinguish local (component) vs global (shared) state. Solutions aim to manage complexity, avoid prop drilling, improve predictability. React State Sharing

Types of State
  • Local/Component State: Managed within a component (e.g., form input, toggle status). Use framework's built-in state (React `useState`, Vue `ref`, Angular component properties).
  • Cross-Component State: State shared between few related components. Often handled by "lifting state up" to a common ancestor.
  • App-Wide/Global State: Shared across many components, potentially unrelated (e.g., user auth, theme, shopping cart). Requires dedicated solutions.
Challenges Without Libraries
  • Prop Drilling: Passing state down through multiple layers of intermediate components that don't need it. Cumbersome and hard to refactor.
  • Complexity: Tracking where state lives and how it changes becomes difficult in large apps.
  • Debugging: Hard to trace state updates and find the source of bugs.

Dedicated libraries (Context, Redux, Zustand, Pinia, etc.) provide patterns and tools to address these challenges.

React Context API React 16.3+

Built-in way to pass data through component tree without prop drilling. Use `createContext`, ``, `useContext`. Best for low-frequency updates. React Context Docs

Core API
  • `React.createContext(defaultValue)`: Creates a Context object. `defaultValue` is used only when a component has no matching Provider above it.
  • ``: Component that makes the context `value` available to all consuming components deep in its subtree.
  • `useContext(MyContext)`: Hook used in functional components to read the current context value from the nearest matching Provider. Causes re-render when Provider's `value` changes.
  • `` (Legacy): Render prop component for consuming context in class components or where Hooks aren't usable.
// 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 (
    <ThemeContext.Provider value={theme}>
      <ThemeUpdateContext.Provider value={toggleTheme}>
        {children}
      </ThemeUpdateContext.Provider>
    </ThemeContext.Provider>
  );
}

// MyComponent.js
import { useTheme, useThemeUpdate } from './ThemeContext';

function MyComponent() {
  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>
  );
}
Considerations
  • Simpler than Redux for many use cases.
  • 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.
  • Often combined with `useState` or `useReducer` within the Provider component to manage the context state itself.
Redux / RTK

Predictable global state container. Central store, immutable updates via pure reducers triggered by dispatched actions. Redux Toolkit (RTK) simplifies setup. Redux Toolkit Docs

Core Concepts
  • Store: Single object holding the application state. Created with `configureStore` (RTK).
  • Actions: Plain objects describing *what happened*. Have a `type` property (string) and often a `payload`. Action creators generate these objects.
  • Reducers: Pure functions `(previousState, action) => newState`. Specify how state changes in response to actions. Must be immutable (return new state objects/arrays).
  • Dispatch: Function (`store.dispatch(action)`) to send actions to the store, triggering reducers.
  • Selectors: Functions to extract specific pieces of data from the store state. Often memoized (e.g., with Reselect) for performance.
  • Middleware: Enhance `dispatch` to handle side effects (like API calls with `createAsyncThunk`), logging, etc.
Redux Toolkit (RTK) Simplifications
// 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>
  );
}

RTK significantly reduces boilerplate compared to classic Redux. Consider RTK Query for data fetching/caching.

Zustand

Minimalist hook-based state management for React. Unopinionated, fast, less boilerplate than Redux. Uses `create` to build a store hook. Zustand GitHub

Core Concept

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.

// store.js
import { create } from 'zustand';

const useBearStore = create((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 useBearStore;

// MyComponent.jsx
import useBearStore from './store';
import React, { useEffect } from 'react';

function BearCounter() {
  // 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() {
  // 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>
      </>
  );
}
Advantages
  • Simple API, minimal boilerplate.
  • Renders components only when the selected state slice changes.
  • Can be used outside React components.
  • Middleware support (devtools, persist, immer, etc.).
Pinia (Vue)

Official state management library for Vue 3. Intuitive, type-safe, modular store definition. Supports Options & Composition API styles. Pinia Docs

Core Concepts
  • Stores: Defined using `defineStore`. Each store has a unique ID.
  • State: Defined as a function returning the initial state object.
  • Getters: Computed properties based on store state (`computed()` under the hood).
  • Actions: Methods that can contain async operations and modify state.
// 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>

Considered the successor to Vuex for Vue 3.

NgRx (Angular)

Reactive state management for Angular inspired by Redux, using RxJS. Provides Store, Actions, Reducers, Effects (for side effects), Selectors. Opinionated. NgRx Docs

Core Concepts
  • Store: Centralized state container, an RxJS Observable stream.
  • Actions: Unique events describing state changes (`createAction`).
  • Reducers: Pure functions defining state transitions based on actions (`createReducer`, `on`).
  • Selectors: Pure functions to derive slices of state from the store (`createSelector`). Memoized for performance.
  • Effects: Handle side effects (like API calls) triggered by actions, often dispatching new actions upon completion (`createEffect`, uses RxJS operators).

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.

Code examples for Actions, Reducers, Effects, Selectors, and component usage needed.

Ecosystem & Tooling

Package Managers

npm, yarn, pnpm manage project dependencies (`node_modules`) via `package.json`. Install, update, remove packages. Run scripts. npm Docs | Yarn | pnpm

`package.json` Key Fields
  • `name`, `version`: Package identification.
  • `dependencies`: Packages needed for the application to run.
  • `devDependencies`: Packages needed only for development (testing, building, linting).
  • `scripts`: Aliases for common command-line tasks (e.g., `start`, `build`, `test`, `lint`). Run via `npm run `.
  • `main` / `module` / `exports`: Entry points for the package.
  • `type`: `"module"` enables native ES Modules syntax in Node.js. Default is `"commonjs"`.
Common Commands (npm example)
  • `npm install `: Install package as dependency. Add `-D` or `--save-dev` for dev dependency.
  • `npm install`: Install all dependencies from `package.json` and `package-lock.json`.
  • `npm uninstall `: Remove package.
  • `npm update`: Update packages based on `package.json` version ranges.
  • `npm outdated`: Check for outdated packages.
  • `npm run `: Execute script defined in `scripts`.
  • `npx `: Execute package binary without installing globally (e.g., `npx create-react-app my-app`).
Lock Files (`package-lock.json`, `yarn.lock`)

Record exact versions of installed dependencies to ensure consistent installs across different environments/developers. Commit these files to source control.

pnpm

Alternative package manager focusing on disk space efficiency (shared store) and speed.

Module Bundlers

Vite, Webpack, Parcel process modules/assets, bundle for browser, optimize, provide dev server (HMR). Essential for modern frontend dev. Vite | Webpack

Why Bundle?
  • Browsers historically didn't support modules efficiently (or at all).
  • Allows using non-JS assets (CSS, images, fonts) in JS modules.
  • Enables transformations (TypeScript, Babel, Sass/PostCSS).
  • Optimizations: Minification, tree-shaking, code splitting.
Key Tools
  • Webpack: Mature, highly configurable, vast plugin ecosystem. Can be complex. Uses loaders for transformations, plugins for broader tasks.
  • Vite: Modern, extremely fast dev server leveraging native ES Modules. Uses Rollup for production builds. Simpler configuration, opinionated defaults. Excellent DX.
  • Parcel: Zero-configuration bundler. Aims for ease of use.
  • Rollup: Primarily focused on bundling libraries (ESM output), often used under the hood by others (like Vite).
Common Features
  • Development Server: Local server for development.
  • Hot Module Replacement (HMR): Update modules in the browser without full page reload during development.
  • Code Splitting: Break bundle into smaller chunks loaded on demand.
  • Tree Shaking: Eliminate unused code from final bundle.
  • Asset Handling: Importing CSS, images, fonts, etc.
  • Environment Variables: Injecting build-time variables (`process.env` or `import.meta.env`).
Transpilers (Babel)

Babel converts modern JS (ES6+) or syntax extensions (JSX, TypeScript drafts) into backward-compatible versions for older browsers/environments. Babel Docs

Purpose
  • Use latest JavaScript features without waiting for full browser support.
  • Transform syntax extensions like JSX into valid JavaScript.
  • Can polyfill missing features (using `core-js`).
Core Concepts
  • Presets: Pre-defined sets of plugins (e.g., `@babel/preset-env` for latest JS, `@babel/preset-react` for JSX, `@babel/preset-typescript`).
  • Plugins: Handle specific transformations (e.g., `@babel/plugin-transform-arrow-functions`).
  • Configuration: Usually via `babel.config.js` or `.babelrc` file.
  • Integration: Used within build tools (Webpack loaders, Vite plugins) or run via CLI.
`@babel/preset-env`

Key preset that automatically determines necessary transformations and polyfills based on target browsers (often configured via `browserslist`).

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.

Linters & Formatters

ESLint finds errors/style issues. Prettier enforces consistent code style automatically. Essential for code quality and team collaboration. ESLint | Prettier

ESLint
  • Purpose: Static analysis to find potential bugs, enforce coding standards, identify anti-patterns.
  • Configuration: 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`).
  • Rules: Granular control over specific checks (e.g., `no-unused-vars`, `eqeqeq`). Can be turned off, set to warn, or error.
  • Fixing: Can automatically fix some reported issues (`--fix` flag).
Prettier
  • Purpose: Opinionated code formatter. Parses code and re-prints it according to its consistent style rules. Focuses purely on formatting, not code quality rules.
  • Configuration: Minimal options via `.prettierrc.js`, etc. (e.g., `tabWidth`, `semi`, `singleQuote`).
  • Integration: 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).
  • Usage: Run via CLI, integrate with IDEs (format on save), use in pre-commit hooks (with tools like Husky/lint-staged).

Using ESLint for code quality/errors and Prettier for formatting is a common and effective combination.

Node.js (Frontend Tooling)

Node.js runtime is essential for the frontend ecosystem. Powers package managers (npm), build tools (Vite, Webpack), task runners, linters, testing frameworks. Node.js

Role in Frontend Development
  • Runtime Environment: Executes the JavaScript code of build tools, linters, test runners, etc., outside the browser.
  • Package Management: npm (Node Package Manager) is bundled with Node.js, enabling installation and management of project dependencies.
  • Build Process: Bundlers like Webpack and Vite are Node.js applications.
  • Server-Side Rendering (SSR): Frameworks like Next.js and Nuxt.js run on Node.js to render pages on the server.
  • API Mocking/Development Servers: Tools for creating local development servers often run on Node.js.

While frontend code ultimately runs in the browser, the entire development toolchain relies heavily on Node.js. Use Node Version Manager (nvm) to manage multiple Node versions easily.

Browser DevTools

Essential tools in browsers (Chrome, Firefox, Edge) for debugging, inspection (DOM/CSS), profiling, network analysis. Crucial for frontend development. Chrome DevTools

Key Panels & Uses
  • Elements: Inspect/edit live DOM tree, view/edit CSS styles, check computed styles, accessibility properties.
  • Console: View `console.log/warn/error` messages, execute JS snippets, inspect JS objects, monitor events.
  • Sources: Set breakpoints, step through JS code, inspect call stack and scope variables, view source maps.
  • Network: Inspect HTTP requests/responses (headers, body, timing), filter requests, throttle network speed, block requests.
  • Performance: Record and analyze runtime performance (JS execution, rendering, painting), identify bottlenecks, detect layout shifts.
  • Memory: Profile memory usage, detect memory leaks, analyze heap snapshots.
  • Application: Inspect/manage storage (localStorage, sessionStorage, IndexedDB, cookies), service workers, manifest files, cache storage.
  • Lighthouse: (Chrome) Run audits for Performance, Accessibility, Best Practices, SEO, PWA readiness.
Framework Extensions

Install browser extensions like React Developer Tools, Vue.js devtools, Angular DevTools for framework-specific inspection (component hierarchy, state, props).

Testing Frameworks

Verify code correctness. Jest/Vitest (Unit/Integration), Testing Library (Components), Cypress/Playwright (E2E). Essential for robust applications. Jest | Testing Library | Playwright

Levels of Testing
  • Unit Tests: Isolate and test small units (functions, modules). Fast, easy to write. Use test runners like Jest, Vitest, Mocha.
  • Integration Tests: Test interactions between multiple units/modules.
  • Component Tests: 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.
  • End-to-End (E2E) Tests: Automate browser interaction to test complete user flows. Slower, more brittle, but essential for critical paths. Use Cypress, Playwright.
Key Tools & Libraries
  • Test Runners: Jest, Vitest (Vite-native), Mocha, Jasmine. Provide test structure (`describe`, `it`/`test`), assertions, mocking.
  • Assertion Libraries: Built into Jest/Vitest. Chai is popular standalone.
  • Mocking/Stubbing: Jest built-ins, Sinon.JS. Replace dependencies for isolated testing.
  • Testing Library: Family of libraries (`@testing-library/react`, etc.) promoting testing components via user interactions, querying by accessible roles/text.
  • E2E Tools: Cypress (runs in browser), Playwright (controls browser externally, cross-browser).
// 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);
// });
TypeScript Integration

TypeScript adds static typing to JS. Improves maintainability, catches errors early. Transpiled to JS via TSC or build tools. TypeScript Docs

Benefits
  • Catch type errors during development (compile-time).
  • Improved code readability and self-documentation.
  • Enhanced IDE support (autocompletion, refactoring).
  • Better maintainability for large projects/teams.
Core Concepts
  • Type Annotations: `let name: string = "Alice";`, `function greet(user: { name: string }): void { ... }`
  • Interfaces & Types: Define custom shapes for objects: `interface User { id: number; name: string; }`, `type Point = { x: number; y: number; };`
  • Generics: Create reusable components/functions working over various types: `function identity(arg: T): T { return arg; }`
  • Utility Types: `Partial`, `Required`, `Readonly`, `Pick`, `Omit`, etc.
  • Enums: Named sets of numeric or string constants.
  • Type Inference: TS often infers types automatically.
Setup & Configuration (`tsconfig.json`)

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`.

Integration

Most modern frameworks (React, Vue, Angular, Svelte) have excellent TypeScript support. Build tools (Vite, Webpack) integrate TS compilation seamlessly.

Advanced Concepts & Patterns

Performance Optimization

Techniques for faster load/runtime. Includes code splitting, lazy loading, memoization, image optimization, virtualization, efficient data fetching. web.dev Performance

Loading Performance
  • Code Splitting: Break large JS bundles into smaller chunks loaded on demand (route-based or component-based). Supported by modern bundlers.
  • Lazy Loading: Defer loading non-critical resources (components via `React.lazy`/dynamic `import()`, images via `loading="lazy"` attribute).
  • Tree Shaking: Bundler removes unused code. Ensure code is statically analyzable (use ESM).
  • Minification/Compression: Reduce file sizes (Terser for JS, CSSNano, Brotli/Gzip on server).
  • Image Optimization: Use appropriate formats (WebP, AVIF), compression, responsive images (`srcset`, ``).
  • Critical CSS: Inline essential CSS for initial render.
  • Caching: Leverage browser caching (HTTP headers) and CDNs.
  • Preloading/Prefetching: Hint browser about resources needed soon (``).
Runtime Performance
  • Memoization: Avoid recomputing expensive values or re-rendering components if props/inputs haven't changed (`React.memo`, `useMemo`, `useCallback`).
  • Virtualization (Windowing): Render only visible items in long lists/tables (`react-window`, `tanstack-virtual`).
  • Debouncing/Throttling: Limit frequency of expensive event handlers (e.g., scroll, resize).
  • Efficient DOM Updates: Minimize direct DOM manipulation (frameworks help). Avoid layout thrashing.
  • Web Workers: Offload CPU-intensive tasks from the main thread.
  • Optimizing Data Fetching: Avoid waterfalls, use caching (React Query, SWR).

Measure using DevTools (Performance, Lighthouse), WebPageTest, Core Web Vitals.

Web Performance Metrics

Quantify user experience. Key metrics include Core Web Vitals (LCP, FID/INP, CLS), TTFB, FCP. Measured via lab (Lighthouse) & field (RUM) data. web.dev Vitals

Core Web Vitals (CWV)
  • Largest Contentful Paint (LCP): Loading performance. Time to render the largest image or text block visible within the viewport. (Good: <= 2.5s)
  • First Input Delay (FID) / Interaction to Next Paint (INP): Interactivity. FID measures delay from first interaction to browser response (Good: <= 100ms). INP (newer, replacing FID) measures overall responsiveness to interactions. (Good: <= 200ms)
  • Cumulative Layout Shift (CLS): Visual stability. Measures unexpected layout shifts during page lifespan. (Good: <= 0.1)
Other Important Metrics
  • Time to First Byte (TTFB): Server responsiveness. Time between request and first byte of response.
  • First Contentful Paint (FCP): Perceived load speed. Time until *any* content (text, image) is rendered.
  • Time to Interactive (TTI): Load responsiveness. Time until page is visually rendered *and* reliably responsive to user input.
Measurement
  • Lab Data: Controlled environment testing (Lighthouse in DevTools, WebPageTest). Good for debugging.
  • Field Data (Real User Monitoring - RUM): Data from actual users (Chrome User Experience Report - CrUX, analytics tools). Reflects real-world performance.
Security Best Practices

Protect against common web vulnerabilities like XSS (Cross-Site Scripting), CSRF (Cross-Site Request Forgery). Sanitize inputs, use secure headers, manage dependencies. OWASP Top 10

Common Frontend Vulnerabilities & Mitigations
  • Cross-Site Scripting (XSS): Injecting malicious scripts into content shown to other users.
    • Mitigation: 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.
  • Cross-Site Request Forgery (CSRF): Tricking a logged-in user's browser into making an unwanted request to a site they're authenticated on.
    • Mitigation: Primarily server-side concern. Use anti-CSRF tokens (Synchronizer Token Pattern). Check `Origin` / `Referer` headers (less reliable). Use `SameSite` cookie attribute (`Lax` or `Strict`).
  • Insecure Direct Object References (IDOR): Exposing internal implementation objects (like file paths or database keys) that allow attackers to manipulate references. (More backend, but frontend can expose IDs).
  • Clickjacking: Tricking users into clicking something different from what they perceive.
    • Mitigation: Use `X-Frame-Options` or CSP `frame-ancestors` header to prevent embedding in malicious frames.
  • Dependency Vulnerabilities: Using third-party libraries with known security flaws.
    • Mitigation: Regularly audit dependencies (`npm audit`, `yarn audit`). Keep packages updated. Use tools like Snyk.
General Practices
  • Validate and sanitize all user input (client-side validation is for UX, server-side is crucial).
  • Use HTTPS everywhere.
  • Implement appropriate Content Security Policy (CSP).
  • Securely handle authentication tokens (e.g., store in `HttpOnly`, `Secure`, `SameSite` cookies or secure browser storage with caution).
  • Don't expose sensitive data or API keys in frontend code.
Accessibility (a11y)

Design usable web apps for everyone, including those with disabilities. Use semantic HTML, ARIA, ensure keyboard navigation, focus management, color contrast. MDN Accessibility | WCAG

Key Principles (WCAG - POUR)
  • Perceivable: Information must be presentable to users in ways they can perceive (e.g., alt text for images, captions for videos, sufficient contrast).
  • Operable: UI components and navigation must be operable (e.g., keyboard accessibility, sufficient time, no seizure triggers, clear navigation).
  • Understandable: Information and operation of UI must be understandable (e.g., clear language, predictable behavior, input assistance).
  • Robust: Content must be robust enough to be interpreted reliably by a wide variety of user agents, including assistive technologies.
Practical Steps for Developers
  • Semantic HTML: Use elements like `
  • ARIA Roles & Attributes: 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. ARIA Docs
  • Keyboard Navigation: All interactive elements must be reachable and operable using the Tab key (and Shift+Tab), Enter, Spacebar. Ensure logical focus order.
  • Focus Management: Provide clear visual focus indicators (`:focus-visible`). Programmatically manage focus in SPAs after route changes or modal dialogs appear.
  • Forms & Labels: Always associate `
  • Images & Media: Provide descriptive `alt` text for meaningful images. Provide captions and transcripts for audio/video.
  • Color Contrast: Ensure sufficient contrast ratio (WCAG AA: 4.5:1 for normal text, 3:1 for large text). Use tools to check.
  • Testing: Automated tools (Axe, Lighthouse), manual keyboard testing, screen reader testing (NVDA, VoiceOver, JAWS).
Progressive Web Apps (PWAs)

Web apps using modern APIs for app-like experience: installable, offline capable (Service Workers), reliable. Requires HTTPS, Manifest. web.dev PWAs

Core Technologies
  • Service Workers: JS scripts acting as proxy servers between browser and network. Run in background. Key for offline caching (Cache Storage API), push notifications, background sync. Service Workers
  • Web App Manifest (`manifest.json`): JSON file providing app information (name, icons, start URL, display mode, theme color) allowing installation to home screen/desktop. Web App Manifest
  • HTTPS: Required for Service Workers and installability prompts.
Key Capabilities & Benefits
  • Installable: Users can add the PWA to their home screen/app list.
  • Offline Capable: Service workers cache assets/data, allowing app to work without network connection (or under poor conditions).
  • App-like Feel: Can run in standalone window (`display: standalone`), use device features.
  • Discoverable & Linkable: Still a web app, discoverable via search engines, shareable via URL.
  • Engaging: Can receive Push Notifications (Push API + Service Worker).
  • Always Up-to-date: Service worker update process allows background updates.

Framework CLIs (Create React App, Angular CLI, Vue CLI) often provide PWA setup options. Libraries like Workbox simplify service worker implementation.

SSR / SSG / CSR

Rendering Strategies: CSR (Client-Side), SSR (Server-Side Rendering), SSG (Static Site Generation). Impact SEO, performance (TTFB, FCP, TTI). Meta-frameworks help. web.dev Rendering

Rendering Strategies
  • Client-Side Rendering (CSR): Default for many SPAs (React, Vue, Angular basic setup). Browser downloads minimal HTML + JS bundle. JS fetches data and renders content in the browser.
    • Pros: Rich interactivity after load, cheaper hosting.
    • Cons: Slow initial load (blank screen), poor SEO without workarounds, requires JS.
  • Server-Side Rendering (SSR): Render page HTML on the server for each request. Browser receives full HTML content, then "hydrates" (attaches event listeners, makes it interactive).
    • Pros: Faster FCP/LCP, better SEO, works without JS initially.
    • Cons: Slower TTFB (server work), more complex server setup, full page reload on navigation (unless paired with client-side routing).
  • Static Site Generation (SSG): Pre-render all pages to static HTML files at build time. Serve files directly from CDN.
    • Pros: Fastest possible TTFB/FCP/LCP, best SEO, secure, cheap hosting.
    • Cons: Requires rebuild for content changes, not suitable for highly dynamic/personalized content per request.
  • Incremental Static Regeneration (ISR): (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.
  • Streaming SSR: Send HTML in chunks as it's rendered on the server, improving TTFB/FCP.
Meta-Frameworks

Frameworks built on top of UI libraries (React, Vue, Svelte) that provide integrated solutions for routing, data fetching, and rendering strategies:

  • Next.js (React): Supports SSR, SSG, ISR, API Routes, Routing.
  • Nuxt (Vue): Supports SSR, SSG, API Routes, Routing.
  • SvelteKit (Svelte): Supports SSR, SSG, API Routes, Routing.
  • Remix (React): Focuses on web standards, SSR, nested routing, data loading/mutations.
  • Astro: Content-focused sites, partial hydration ("Islands Architecture"), framework-agnostic.

Choice depends on content dynamism, SEO needs, performance goals, infrastructure.

Design Patterns in JS

Reusable solutions to common programming problems. Includes Creational (Singleton), Structural (Module, Facade), Behavioral (Observer, Command) patterns adapted for JS. Refactoring Guru (JS)

Common Patterns (Examples)
  • Module Pattern: Encapsulate private state/methods using closures or ES Modules.
    // 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';
    
  • Singleton Pattern: 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).
  • Observer Pattern: Define a one-to-many dependency where observers are notified of state changes in a subject. (Foundation for event listeners, reactive systems like RxJS).
  • Facade Pattern: Provide a simplified interface to a complex subsystem.
  • Command Pattern: Encapsulate a request as an object, allowing parameterization, queuing, logging.
  • Factory Pattern / Method: Create objects without specifying the exact class.

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).

Key Considerations for Frontend Developers & Architects

Architectural Decision Points

Strategic choices impacting frontend application scalability, maintainability, performance, security, and developer experience (DX). Includes framework selection, state/data management, build tooling, testing, rendering strategy. Frontend Roadmap

Core Decision Areas
  • Framework/Library Choice: Assess React, Vue, Angular, Svelte, or others based on project complexity, team skills, performance needs, ecosystem maturity, community support, long-term maintenance goals.
  • State Management Strategy: 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)?
  • Rendering Strategy (CSR/SSR/SSG/ISR): 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).
  • Component Architecture & Design Patterns: Atomic Design, Presentational/Container components, state colocation, hooks/composables for logic reuse. Establish clear conventions.
  • Data Fetching Approach: 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)?
  • Build Tooling & Configuration: Vite vs. Webpack vs. others. Balance DX (dev server speed, HMR) with build optimization capabilities and configuration complexity.
  • Testing Strategy: Define testing pyramid/trophy balance (Unit, Integration, Component, E2E). Select appropriate tools. Establish coverage goals and CI integration.
  • TypeScript vs JavaScript: Weigh benefits of static typing (safety, refactoring, tooling) against potential friction or learning curve for the team. Configure strictness appropriately.
  • Monorepo vs. Polyrepo: Choose code organization strategy based on project/team size, shared code needs, deployment strategies. Tools like Nx, Turborepo can help manage monorepos.
  • Styling Approach: CSS Modules, CSS-in-JS (Styled Components, Emotion), Utility-first (Tailwind CSS), component library styling (MUI, Bootstrap). Consider performance, DX, maintainability.
  • Performance Budgeting: Set concrete goals for key metrics (Core Web Vitals, bundle sizes) and monitor them continuously.
  • Accessibility (a11y) & Security: Integrate checks and best practices into the development workflow from the start, not as an afterthought.
  • Deployment & Infrastructure: CI/CD pipelines, hosting platforms (Vercel, Netlify, Cloud providers), CDN strategy, environment management.

Architectural decisions involve trade-offs. Document choices and rationale. Revisit decisions as project evolves.