40 Advanced JavaScript Tutorials

40 Advanced JavaScript Tutorials

1. Advanced Prototypes

Prototypes can be dynamically modified to extend object behavior.

Example: Dynamic prototype modification.

function Animal() {}
Animal.prototype.speak = function() { return "Sound"; };
const dog = new Animal();
Animal.prototype.speak = function() { return "Woof"; };
console.log(dog.speak());
Output: Woof

Note: Changes to prototypes affect all instances.

2. Metaprogramming

Metaprogramming manipulates code behavior dynamically.

Example: Dynamic method addition.

const obj = {};
Object.defineProperty(obj, "sayHi", {
value: () => "Hello!",
enumerable: false
});
console.log(obj.sayHi());
Output: Hello!

Note: Use Object.defineProperty for fine-grained control.

3. Symbol Types

Symbols create unique, non-enumerable properties.

Example: Using Symbol.

const sym = Symbol("id");
const obj = { [sym]: 123 };
console.log(obj[sym]);
Output: 123

Note: Symbols prevent property name collisions.

4. Reflect API

Reflect API provides methods for object manipulation.

Example: Using Reflect.

const obj = {};
Reflect.set(obj, "name", "Alice");
console.log(Reflect.get(obj, "name"));
Output: Alice

Note: Reflect methods align with Proxy traps.

5. Advanced Generators

Generators can yield control to other generators.

Example: Delegating generator.

function* subGen() { yield 1; yield 2; }
function* mainGen() { yield* subGen(); yield 3; }
const gen = mainGen();
console.log([...gen]);
Output: [1, 2, 3]

Note: Use yield* for delegation.

6. Async Iterators

Async iterators handle asynchronous iteration.

Example: Async iterator.

const asyncIterable = {
async *[Symbol.asyncIterator]() {
await new Promise(r => setTimeout(r, 1000));
yield 1;
}
};
(async () => {
for await (const value of asyncIterable) {
console.log(value);
}
})();

Note: Use with for await...of.

7. Proxy Traps

Proxy traps customize object operations like property access.

Example: Custom getter trap.

const handler = {
get(target, prop) {
return prop in target ? target[prop] : "Missing";
}
};
const proxy = new Proxy({ name: "Alice" }, handler);
console.log(proxy.name, proxy.age);
Output: Alice Missing

Note: Traps include set, deleteProperty, etc.

8. Advanced Promises

Advanced Promise patterns handle complex async flows.

Example: Promise.allSettled.

const promises = [
Promise.resolve(1),
Promise.reject("Error"),
Promise.resolve(3)
];
Promise.allSettled(promises).then(results => console.log(results));
Output: [{status: "fulfilled", value: 1}, {status: "rejected", reason: "Error"}, {status: "fulfilled", value: 3}]

Note: allSettled waits for all promises.

9. Microtask Queue

Microtasks execute before macrotasks in the event loop.

Example: Microtask vs macrotask.

setTimeout(() => console.log("Macrotask"), 0);
Promise.resolve().then(() => console.log("Microtask"));

Note: Microtasks have higher priority.

10. WebAssembly Basics

WebAssembly runs high-performance code in the browser.

Example: Loading WebAssembly (simulated).

WebAssembly.instantiateStreaming(fetch("module.wasm")).then(result => {
console.log(result.instance.exports.add(2, 3));
});
Output: WebAssembly loaded (simulated)

Note: Requires a .wasm file.

11. SharedArrayBuffer

SharedArrayBuffer enables shared memory between threads.

Example: Shared memory.

const sab = new SharedArrayBuffer(4);
const arr = new Int32Array(sab);
arr[0] = 42;
console.log(arr[0]);
Output: 42

Note: Requires cross-origin isolation.

12. Atomics

Atomics provide atomic operations for SharedArrayBuffer.

Example: Atomic operation.

const sab = new SharedArrayBuffer(4);
const arr = new Int32Array(sab);
Atomics.store(arr, 0, 100);
console.log(Atomics.load(arr, 0));
Output: 100

Note: Prevents race conditions in shared memory.

13. Advanced Event Loop

Advanced event loop techniques manage complex async tasks.

Example: Microtask scheduling.

queueMicrotask(() => console.log("Microtask"));
setTimeout(() => console.log("Macrotask"), 0);

Note: queueMicrotask schedules microtasks directly.

14. Performance Optimization

Optimizations reduce runtime and memory usage.

Example: Efficient loop.

const arr = new Array(1000).fill(1);
const start = performance.now();
arr.forEach(n => n * 2);
console.log(performance.now() - start);
Output: ms

Note: Use for loops for better performance in some cases.

15. Memory Management

Memory management minimizes leaks and optimizes usage.

Example: Avoiding memory leaks.

let obj = { data: new Array(1000000) };
obj = null; // Allow garbage collection
console.log("Memory freed");
Output: Memory freed

Note: Set unused references to null.

16. Advanced Web Workers

Web Workers can handle complex computations off the main thread.

Example: Worker with message passing.

const worker = new Worker(URL.createObjectURL(new Blob(["onmessage = e => postMessage(e.data.map(n => n * 2));"])));
worker.postMessage([1, 2, 3]);
worker.onmessage = e => console.log(e.data);

Note: Workers improve performance for heavy tasks.

17. Service Worker Strategies

Service Workers implement caching strategies for offline support.

Example: Cache-first strategy (simulated).

self.addEventListener("fetch", e => {
e.respondWith(caches.match(e.request).then(response => response || fetch(e.request)));
});
Output: Cache-first strategy (simulated)

Note: Use cache.addAll for pre-caching.

18. Advanced IndexedDB

IndexedDB supports transactions and indexing.

Example: IndexedDB with index (simulated).

const request = indexedDB.open("db");
request.onupgradeneeded = () => {
const db = request.result;
const store = db.createObjectStore("store", { keyPath: "id" });
store.createIndex("name", "name");
};
request.onsuccess = () => console.log("DB ready");
Output: DB ready (simulated)

Note: Indexes improve query performance.

19. WebRTC Basics

WebRTC enables real-time peer-to-peer communication.

Example: RTC connection (simulated).

const pc = new RTCPeerConnection();
pc.onicecandidate = e => console.log(e.candidate);
pc.createOffer().then(offer => pc.setLocalDescription(offer));
Output: ICE candidate generated (simulated)

Note: Requires signaling server for production.

20. WebSocket Scaling

WebSocket scaling handles multiple client connections.

Example: WebSocket reconnection (simulated).

function connect() {
const ws = new WebSocket("ws://example.com");
ws.onclose = () => setTimeout(connect, 1000);
ws.onmessage = e => console.log(e.data);
}
connect();
Output: WebSocket connected (simulated)

Note: Implement reconnection logic for reliability.

21. Custom Elements

Custom Elements create reusable HTML elements.

Example: Defining a custom element.

class MyElement extends HTMLElement {
connectedCallback() {
this.innerHTML = "Hello from custom element!";
}
}
customElements.define("my-element", MyElement);
Output: Hello from custom element!

Note: Extends HTMLElement.

22. Shadow DOM

Shadow DOM encapsulates DOM and styles.

Example: Creating shadow DOM.

class MyComponent extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: "open" });
shadow.innerHTML = "

Shadow content

"; } } customElements.define("my-component", MyComponent);
Output: Shadow content

Note: Use mode: "closed" for private DOM.

23. Advanced Observers

Observers like PerformanceObserver monitor performance metrics.

Example: PerformanceObserver.

const observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => console.log(entry.name));
});
observer.observe({ type: "mark" });
performance.mark("test");

Note: Tracks various performance entries.

24. Functional Reactive

Functional reactive programming manages data streams.

Example: Simple stream (simulated).

function fromEvent(element, event) {
return {
subscribe: callback => element.addEventListener(event, callback)
};
}
fromEvent(document, "click").subscribe(() => console.log("Clicked"));

Note: Libraries like RxJS enhance this pattern.

25. Advanced Currying

Advanced currying creates flexible, reusable functions.

Example: Infinite currying.

function curry(fn) {
return function curried(...args) {
return args.length >= fn.length ? fn(...args) : (...more) => curried(...args, ...more);
};
}
const sum = curry((...args) => args.reduce((a, b) => a + b, 0));
console.log(sum(1)(2)(3)());
Output: 6

Note: Allows partial application indefinitely.

26. Transducers

Transducers transform data in a composable way.

Example: Simple transducer.

const map = fn => reducer => (acc, val) => reducer(acc, fn(val));
const filter = pred => reducer => (acc, val) => pred(val) ? reducer(acc, val) : acc;
const transducer = map(x => x * 2);
console.log([1, 2, 3].reduce(transducer((a, b) => a + b), 0));
Output: 12

Note: Reduces memory usage in pipelines.

27. Lazy Evaluation

Lazy evaluation defers computation until needed.

Example: Lazy sequence.

function* lazyRange(n) {
for (let i = 0; i < n; i++) yield i;
}
const range = lazyRange(1000);
console.log(range.next().value);
Output: 0

Note: Saves memory for large datasets.

28. Advanced Memoization

Advanced memoization handles complex inputs.

Example: Memoizing recursive function.

function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
const fib = memoize(n => n <= 1 ? n : fib(n - 1) + fib(n - 2));
console.log(fib(10));
Output: 55

Note: Cache complex keys with serialization.

29. Monads

Monads encapsulate computations with context.

Example: Maybe monad.

class Maybe {
constructor(value) { this.value = value; }
static of(value) { return new Maybe(value); }
map(fn) { return this.value == null ? this : Maybe.of(fn(this.value)); }
}
const result = Maybe.of(5).map(x => x * 2);
console.log(result.value);
Output: 10

Note: Monads chain operations safely.

30. Functors

Functors map functions over wrapped values.

Example: Simple functor.

class Functor {
constructor(value) { this.value = value; }
static of(value) { return new Functor(value); }
map(fn) { return Functor.of(fn(this.value)); }
}
console.log(Functor.of(5).map(x => x * 2).value);
Output: 10

Note: Functors preserve structure during mapping.

31. Advanced Modules

Advanced modules use dynamic imports and top-level await.

Example: Top-level await (simulated).

const module = await import("./module.js");
console.log(module.default());
Output: Module loaded (simulated)

Note: Requires module script type.

32. Tree Shaking

Tree shaking eliminates unused module code.

Example: Exporting used function (simulated).

export function used() { return "Used"; }
export function unused() { return "Unused"; }
import { used } from "./module.js";
console.log(used());
Output: Used

Note: Requires ES modules and bundlers.

33. Code Splitting

Code splitting divides code into smaller bundles.

Example: Dynamic import for splitting.

import("./module.js").then(module => console.log(module.default()));
Output: Module loaded (simulated)

Note: Improves initial load time.

34. Advanced Regex

Advanced regex uses lookaheads and lookbehinds.

Example: Positive lookahead.

const regex = /(?=\d{4})\w+/;
console.log("1234abc".match(regex));
Output: ["1234abc"]

Note: Lookaheads assert conditions without consuming.

35. Intl Advanced

Intl API supports advanced formatting like plurals.

Example: Plural rules.

const pr = new Intl.PluralRules("en-US");
console.log(pr.select(1), pr.select(2));
Output: one two

Note: Useful for i18n applications.

36. Typed Array Buffers

Typed arrays with ArrayBuffer manipulate raw binary data.

Example: DataView manipulation.

const buffer = new ArrayBuffer(8);
const view = new DataView(buffer);
view.setInt32(0, 42);
console.log(view.getInt32(0));
Output: 42

Note: DataView provides flexible access.

37. BigInt Advanced

BigInt handles arbitrary-precision arithmetic.

Example: Large number operations.

const a = 12345678901234567890n;
const b = BigInt(Number.MAX_SAFE_INTEGER);
console.log(a * b);
Output: 1115739557876543209876543210

Note: Avoid mixing with regular numbers.

38. SIMD Operations

SIMD (Single Instruction, Multiple Data) optimizes parallel computations (simulated).

Example: SIMD vector addition (simulated).

const vec1 = new Float32Array([1, 2, 3, 4]);
const vec2 = new Float32Array([5, 6, 7, 8]);
const result = vec1.map((v, i) => v + vec2[i]);
console.log(result);
Output: [6, 8, 10, 12]

Note: Native SIMD requires WebAssembly.

39. Advanced Error Handling

Advanced error handling uses custom error classes.

Example: Custom error.

class CustomError extends Error {
constructor(message) { super(message); this.name = "CustomError"; }
}
try {
throw new CustomError("Test error");
} catch (e) {
console.log(e.name, e.message);
}
Output: CustomError Test error

Note: Extend Error for specific cases.

40. Micro-Frontends

Micro-frontends split frontend into independent components.

Example: Loading micro-frontend (simulated).

function loadMicroFrontend(url) {
const script = document.createElement("script");
script.src = url;
document.body.appendChild(script);
}
loadMicroFrontend("microfrontend.js");
Output: Micro-frontend loaded (simulated)

Note: Use module federation for real implementations.

Macro Nepal Helper