Advanced JavaScript & Computer Science: SDE-3 Reference
This final section explores engine-level data structures, algorithmic complexity, functional programming concepts, architecture patterns, and clean code standards.
24. Data Structures
Understanding how V8 structures variables in memory is critical for writing high-performance code.
V8 Arrays: Fast Elements vs. Dictionary Elements
V8 optimizes arrays based on their indices:
- Fast Elements: If the array has sequential indices (no holes), V8 allocates a contiguous flat array in memory. Access is $O(1)$ and extremely fast.
- Dictionary (Sparse) Elements: If the array has holes (e.g.
arr[0] = 1; arr[99999] = 2;), V8 converts it into a hash table lookup. This saves memory but degrades access time to $O(1)$ amortized (with hash function overhead).
[!TIP] SDE-3 Guideline: Avoid creating "holey arrays" (e.g.
new Array(10)or deleting elements usingdelete arr[i]). Usearr.push()or pre-allocate with small elements to keep the array in Fast Elements mode.
25. Expensive Operations & Big O Notation
Big O Notation describes the limiting behavior of an algorithm as the input size ($N$) scales.
| Notation | Name | JS Context Example |
|---|---|---|
| $O(1)$ | Constant | Accessing object property, array index lookup. |
| $O(\log N)$ | Logarithmic | Binary search. |
| $O(N)$ | Linear | Iterating array (find, forEach). |
| $O(N \log N)$ | Pseudo-linear | Sorting array (Array.prototype.sort). |
| $O(N^2)$ | Quadratic | Nested loops. |
Browser Thread Freezing & Web Worker Offloading
Any execution path in the event loop exceeding 50ms is considered a Long Task. Because JavaScript shares a single thread with rendering, a long-running $O(N^2)$ loop freezes the user interface (the compositor cannot paint, resulting in dropped frames).
Always offload expensive operations (e.g. cryptographic processing, heavy image manipulation) to a background thread using Web Workers.
26. Algorithms
Algorithms are structured steps to solve computational problems.
Array Sorting in JS (V8's Timsort)
V8's Array.prototype.sort() uses Timsort (hybrid of Merge Sort and Insertion Sort).
- Time Complexity: $O(N \log N)$ worst/average case, $O(N)$ best case.
- Stability: It is a stable sort algorithm (preserves original order of equal keys).
// Binary Search Implementation in JS
function binarySearch(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left <= right) {
const mid = (left + right) >> 1; // Bitwise division by 2
if (arr[mid] === target) return mid;
if (arr[mid] < target) left = mid + 1;
else right = mid - 1;
}
return -1;
}27. Inheritance, Polymorphism & Code Reuse
Classical vs. Prototypal Reusability
- Classical (Class-Based): Static, class blueprint contracts.
- Prototypal: Dynamic linkage where objects inherit directly from other objects.
Composition Over Inheritance
Senior designs prefer composing behavior over deep inheritance chains, avoiding tight coupling.
// Composition using Mixins
const canFly = (state) => ({
fly: () => console.log(`${state.name} is flying!`)
});
const canSwim = (state) => ({
swim: () => console.log(`${state.name} is swimming!`)
});
// Creating a duck character
const createDuck = (name) => {
const state = { name };
return Object.assign({}, canFly(state), canSwim(state));
};
const duck = createDuck("Mallard");
duck.fly();
duck.swim();28. Design Patterns
Design patterns provide reusable templates to solve common structural and architectural challenges.
The Pub-Sub (Observer) Pattern
Useful for event-driven UI architectures, decoupling event emitters from listeners.
class EventEmitter {
constructor() {
this.events = new Map();
}
subscribe(event, callback) {
if (!this.events.has(event)) {
this.events.set(event, new Set());
}
this.events.get(event).add(callback);
// Return unsubscribe function
return () => this.events.get(event).delete(callback);
}
emit(event, ...args) {
if (!this.events.has(event)) return;
this.events.get(event).forEach((cb) => {
try {
cb(...args);
} catch (e) {
console.error(e);
}
});
}
}29. Partial Application, Currying, Compose & Pipe
These are foundational tools in functional programming.
1. Currying
Currying transforms a function of multiple arguments into a chain of nesting single-argument functions: $f(a, b, c) \to f(a)(b)(c)$.
const curry = (fn) => {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
}
return (...nextArgs) => curried.apply(this, [...args, ...nextArgs]);
};
};
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3)); // 62. Compose and Pipe
Functions can be composed to chain data processing:
compose: Right-to-left evaluation.pipe: Left-to-right evaluation.
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);
const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);
const double = x => x * 2;
const addOne = x => x + 1;
const runPipe = pipe(double, addOne); // (x * 2) + 1
console.log(runPipe(5)); // 1130. map, reduce, filter Performance
While map, reduce, and filter improve code readability, they introduce performance trade-offs:
- Allocations: Every
.map()or.filter()returns a brand-new array. Chaining calls (e.g.arr.filter().map().reduce()) creates multiple intermediate arrays, putting pressure on the V8 Young Generation Garbage Collector (Scavenger). - Call Overhead: They execute a callback function for every element, which can slow down hot paths.
// Performance Critical Path: Use manual loops to avoid intermediate array allocations
let sum = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] > 10) {
sum += arr[i] * 2;
}
}31. State Mutation & Event Propagation
Immutability & Reference Checking
In modern state management frameworks (React, Redux), state changes are validated using shallow reference comparisons (prevObj !== nextObj). Mutating properties directly without reassigning the reference breaks update lifecycles.
Event Propagation Phases
When a DOM event fires, it propagates through three phases:
- Capturing Phase: The event descends from the
Windowobject down to the target element's parent. - Target Phase: The event reaches the target element.
- Bubbling Phase: The event bubbles up from the target element back to
Window.
// Event Delegation Pattern (Using Bubbling)
document.getElementById("parent-list").addEventListener("click", (event) => {
if (event.target.tagName === "LI") {
console.log(`Clicked list item: ${event.target.textContent}`);
}
});32. Clean Code & SOLID
Senior developers prioritize code maintainability, testing boundaries, and readability.
- S (Single Responsibility): A module or class should have exactly one reason to change.
- O (Open/Closed): Software entities should be open for extension, but closed for modification.
- L (Liskov Substitution): Derived classes must be completely substitutable for their base classes.
- I (Interface Segregation): Rely on small, client-specific interfaces rather than fat, monolithic ones.
- D (Dependency Inversion): Depend on abstractions rather than concrete implementations.
33. Computed Property Names
Introduced in ES6, Computed Property Names allow object property keys to be evaluated dynamically from expressions at runtime.
const dynamicPrefix = "sde3_";
const userRecord = {
[dynamicPrefix + "id"]: "007",
[dynamicPrefix + "name"]: "Antigravity"
};
console.log(userRecord.sde3_id); // "007"Mark this page when you finish learning it.
Spotted something unclear or wrong on this page?