Skip to content

JavaScript Advanced Guide

Mattscreative edited this page Feb 21, 2026 · 1 revision

JavaScript Advanced Guide

Table of Contents


Introduction

This guide covers advanced JavaScript concepts including object-oriented programming, the prototype system, closures, the event loop, design patterns, and performance optimization. These concepts will help you write more sophisticated and efficient code.


Object-Oriented Programming (OOP)

Classes

Classes in JavaScript provide a cleaner syntax for creating objects and implementing inheritance:

// Class declaration
class Person {
    // Constructor - called when creating new instance
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    
    // Method
    greet() {
        return `Hello, my name is ${this.name}`;
    }
    
    // Another method
    celebrateBirthday() {
        this.age++;
        return `Happy birthday! Now I am ${this.age}`;
    }
}

// Creating an instance
const alice = new Person("Alice", 25);
console.log(alice.greet());  // "Hello, my name is Alice"
console.log(alice.celebrateBirthday());  // "Happy birthday! Now I am 26"

// Class expression
const Animal = class {
    constructor(species) {
        this.species = species;
    }
    
    speak() {
        return `${this.species} makes a sound`;
    }
};

Inheritance

Use extends to create a class that inherits from another:

// Parent class
class Animal {
    constructor(name) {
        this.name = name;
    }
    
    speak() {
        return `${this.name} makes a sound`;
    }
    
    move() {
        return `${this.name} moves`;
    }
}

// Child class
class Dog extends Animal {
    constructor(name, breed) {
        super(name);  // Call parent constructor
        this.breed = breed;
    }
    
    // Override parent method
    speak() {
        return `${this.name} barks`;
    }
    
    // New method specific to Dog
    fetch() {
        return `${this.name} fetches the ball`;
    }
}

const dog = new Dog("Buddy", "Golden Retriever");
console.log(dog.speak());  // "Buddy barks"
console.log(dog.move());   // "Buddy moves" (inherited)
console.log(dog.fetch());  // "Buddy fetches the ball"
console.log(dog instanceof Dog);    // true
console.log(dog instanceof Animal); // true

Private Fields

Private fields (prefixed with #) encapsulate data:

class BankAccount {
    // Private fields
    #balance;
    #transactions = [];
    
    constructor(initialBalance = 0) {
        this.#balance = initialBalance;
    }
    
    // Public method to get balance
    getBalance() {
        return this.#balance;
    }
    
    // Deposit money
    deposit(amount) {
        if (amount <= 0) {
            throw new Error("Deposit amount must be positive");
        }
        this.#balance += amount;
        this.#transactions.push({ type: 'deposit', amount });
        return this.#balance;
    }
    
    // Withdraw money
    withdraw(amount) {
        if (amount <= 0) {
            throw new Error("Withdrawal amount must be positive");
        }
        if (amount > this.#balance) {
            throw new Error("Insufficient funds");
        }
        this.#balance -= amount;
        this.#transactions.push({ type: 'withdraw', amount });
        return this.#balance;
    }
    
    // Private method
    #logTransaction(type, amount) {
        console.log(`${type}: $${amount}`);
    }
}

const account = new BankAccount(1000);
console.log(account.getBalance());  // 1000
account.deposit(500);  // 1500
// console.log(account.#balance);  // SyntaxError - can't access private field
// console.log(account.#transactions);  // SyntaxError

Static Methods and Properties

Static members belong to the class itself, not instances:

class MathUtils {
    static PI = 3.14159;
    
    static add(a, b) {
        return a + b;
    }
    
    static factorial(n) {
        if (n <= 1) return 1;
        return n * this.factorial(n - 1);
    }
    
    // Static factory method
    static fromDegrees(degrees) {
        return degrees * (MathUtils.PI / 180);
    }
}

console.log(MathUtils.PI);  // 3.14159
console.log(MathUtils.add(2, 3));  // 5
console.log(MathUtils.factorial(5));  // 120
console.log(MathUtils.fromDegrees(90));  // ~1.57

// Cannot call static on instance
const utils = new MathUtils();
// utils.add(2, 3);  // TypeError

Getters and Setters

Getters and setters provide controlled access to properties:

class Temperature {
    constructor(celsius) {
        this.celsius = celsius;
    }
    
    // Getter
    get fahrenheit() {
        return (this.celsius * 9/5) + 32;
    }
    
    // Setter
    set fahrenheit(value) {
        this.celsius = (value - 32) * 5/9;
    }
    
    get kelvin() {
        return this.celsius + 273.15;
    }
    
    set kelvin(value) {
        this.celsius = value - 273.15;
    }
}

const temp = new Temperature(25);
console.log(temp.celsius);    // 25
console.log(temp.fahrenheit); // 77
console.log(temp.kelvin);     // 298.15

temp.fahrenheit = 100;
console.log(temp.celsius);   // ~37.78

Prototype System

Every JavaScript object has a prototype, which is another object from which it inherits properties.

Prototype Chain

// Every object has a prototype
const obj = {};
console.log(obj.__proto__);  // Object.prototype
console.log(obj.__proto__.__proto__);  // null

// Arrays inherit from Array.prototype
const arr = [1, 2, 3];
console.log(arr.__proto__ === Array.prototype);  // true
console.log(arr.__proto__.__proto__ === Object.prototype);  // true

// Functions inherit from Function.prototype
function foo() {}
console.log(foo.__proto__ === Function.prototype);  // true

Prototypal Inheritance

// Create object with specific prototype
const animal = {
    speak() {
        return `${this.name} makes a sound`;
    },
    move() {
        return `${this.name} moves`;
    }
};

const dog = Object.create(animal);
dog.name = "Buddy";
dog.breed = "Golden Retriever";

console.log(dog.speak());  // "Buddy makes a sound"
console.log(dog.move());   // "Buddy moves"
console.log(dog.hasOwnProperty('name'));  // true
console.log(dog.hasOwnProperty('speak'));  // false (inherited)
console.log(animal.isPrototypeOf(dog));  // true

Object.create

// Creating inheritance chain
const Mammal = {
    isWarmBlooded: true,
    giveBirth() {
        return `${this.name} gives live birth`;
    }
};

const Primate = Object.create(Mammal);
Primate.hasOpposableThumbs = true;
Primate.useTools = function() {
    return `${this.name} uses tools`;
};

const Human = Object.create(Primate);
Human.name = "Alice";
Human.speak = function() {
    return `${this.name} speaks`;
};

console.log(Human.isWarmBlooded);  // true (inherited from Mammal)
console.log(Human.hasOpposableThumbs);  // true (inherited from Primate)
console.log(Human.useTools());  // "Alice uses tools"
console.log(Human.speak());  // "Alice speaks"
console.log(Human.giveBirth());  // "Alice gives live birth"

Closures and Scope

Understanding Closures

A closure is a function that remembers its outer variables even after the outer function has returned:

// Simple closure example
function createCounter() {
    let count = 0;
    
    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();
console.log(counter());  // 1
console.log(counter());  // 2
console.log(counter());  // 3

// Each call creates a new closure
const counter2 = createCounter();
console.log(counter2());  // 1 (separate count)

// Closure with parameters
function createMultiplier(factor) {
    return function(number) {
        return number * factor;
    };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5));  // 10
console.log(triple(5));  // 15

Practical Closure Examples

// Private variables via closure
function createBankAccount(initialBalance) {
    let balance = initialBalance;
    
    return {
        deposit(amount) {
            if (amount > 0) {
                balance += amount;
                return balance;
            }
            throw new Error("Invalid amount");
        },
        withdraw(amount) {
            if (amount > 0 && amount <= balance) {
                balance -= amount;
                return balance;
            }
            throw new Error("Invalid amount or insufficient funds");
        },
        getBalance() {
            return balance;
        }
    };
}

const account = createBankAccount(100);
console.log(account.getBalance());  // 100
account.deposit(50);
console.log(account.getBalance());  // 150
account.withdraw(75);
console.log(account.getBalance());  // 75

// Event handler with closure
function setupButtonHandler(buttonId, count) {
    const button = document.getElementById(buttonId);
    let clickCount = count || 0;
    
    button.addEventListener('click', function() {
        clickCount++;
        console.log(`Button clicked ${clickCount} times`);
    });
}

// Function factory
function createGame(name) {
    let score = 0;
    
    return {
        name,
        increaseScore(points) {
            score += points;
            console.log(`${name}: ${score}`);
        },
        reset() {
            score = 0;
        }
    };
}

const game1 = createGame("Game 1");
const game2 = createGame("Game 2");
game1.increaseScore(10);  // "Game 1: 10"
game2.increaseScore(20);  // "Game 2: 20"

Memory Considerations

// Potential memory leak - closure holding reference
function leakMemory() {
    const largeData = new Array(1000000).fill("data");
    
    return function() {
        return largeData[0];  // Keeps largeData in memory
    };
}

// Better approach - avoid holding unnecessary references
function noLeakMemory() {
    const largeData = new Array(1000000).fill("data");
    
    return function() {
        return largeData[0];  // Necessary reference
    };
    // largeData becomes eligible for GC after function returns
}

The this Keyword Deep Dive

Binding this

// In methods, 'this' refers to the object
const person = {
    name: "Alice",
    greet() {
        return `Hello, I'm ${this.name}`;
    }
};
console.log(person.greet());  // "Hello, I'm Alice"

// When extracted, 'this' loses context
const greetFn = person.greet;
console.log(greetFn());  // "Hello, I'm undefined" (or error in strict mode)

// Solution 1: Bind
const boundGreet = person.greet.bind(person);
console.log(boundGreet());  // "Hello, I'm Alice"

// Solution 2: Arrow function in object
const person2 = {
    name: "Bob",
    greet: () => {
        return `Hello, I'm ${this.name}`;  // 'this' is lexically bound
    }
};

call, apply, and bind

function greet(greeting, punctuation) {
    return `${greeting}, ${this.name}${punctuation}`;
}

const person = { name: "Alice" };

// call - invoke with specific 'this' and arguments
console.log(greet.call(person, "Hello", "!"));  // "Hello, Alice!"

// apply - invoke with specific 'this' and array of arguments
console.log(greet.apply(person, ["Hi", "."]));  // "Hi, Alice."

// bind - create new function with bound 'this'
const boundGreet = greet.bind(person);
console.log(boundGreet("Howdy", "?"));  // "Howdy, Alice?"

// Partial application with bind
const greetAlice = greet.bind(person, "Hello");
console.log(greetAlice("!"));  // "Hello, Alice!"

Asynchronous Patterns

Event Loop

// JavaScript is single-threaded but handles async via event loop
console.log("1. Start");

setTimeout(() => {
    console.log("2. Timeout callback");
}, 0);

Promise.resolve().then(() => {
    console.log("3. Promise resolved");
});

console.log("4. End");

// Output order:
// 1. Start
// 4. End
// 3. Promise resolved (microtask)
// 2. Timeout callback (macrotask)

Callback Queue

// Microtasks (Promises, queueMicrotask)
Promise.resolve().then(() => console.log("Promise 1"));
queueMicrotask(() => console.log("Microtask"));

// Macrotasks (setTimeout, setInterval, I/O)
setTimeout(() => console.log("Timeout"), 0);

// Execution order
console.log("Start");

setTimeout(() => console.log("Timeout"), 0);

Promise.resolve().then(() => console.log("Promise 1"))
    .then(() => Promise.resolve().then(() => console.log("Promise 2")));

queueMicrotask(() => console.log("Microtask"));

console.log("End");

// Output:
// Start
// End
// Promise 1
// Promise 2
// Microtask
// Timeout

Advanced Promise Patterns

// Promise timeout
function withTimeout(promise, ms) {
    const timeout = new Promise((_, reject) => {
        setTimeout(() => reject(new Error("Timeout")), ms);
    });
    
    return Promise.race([promise, timeout]);
}

// Retry with exponential backoff
async function retry(fn, maxAttempts = 3, delay = 1000) {
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
        try {
            return await fn();
        } catch (error) {
            if (attempt === maxAttempts) throw error;
            await new Promise(r => setTimeout(r, delay * attempt));
        }
    }
}

// Promise queue - run promises sequentially
async function runSequentially(promises) {
    const results = [];
    for (const promise of promises) {
        results.push(await promise);
    }
    return results;
}

// Promise cache
const promiseCache = new Map();

async function fetchWithCache(url) {
    if (promiseCache.has(url)) {
        return promiseCache.get(url);
    }
    
    const promise = fetch(url).then(r => r.json());
    promiseCache.set(url, promise);
    return promise;
}

Design Patterns

Module Pattern

// Using IIFE to create private scope
const CounterModule = (function() {
    // Private state
    let count = 0;
    
    // Private function
    function validate(value) {
        return typeof value === 'number' && !isNaN(value);
    }
    
    // Public API
    return {
        increment(value = 1) {
            if (validate(value)) {
                count += value;
                return count;
            }
            return count;
        },
        decrement(value = 1) {
            if (validate(value)) {
                count -= value;
                return count;
            }
            return count;
        },
        getCount() {
            return count;
        },
        reset() {
            count = 0;
            return count;
        }
    };
})();

console.log(CounterModule.increment());  // 1
console.log(CounterModule.increment(5)); // 6
console.log(CounterModule.getCount());   // 6
console.log(CounterModule.count);        // undefined (private)

Singleton

// Singleton using class
class Singleton {
    static #instance = null;
    
    constructor() {
        if (Singleton.#instance) {
            return Singleton.#instance;
        }
        Singleton.#instance = this;
        this.data = {};
    }
    
    set(key, value) {
        this.data[key] = value;
    }
    
    get(key) {
        return this.data[key];
    }
}

const a = new Singleton();
const b = new Singleton();
console.log(a === b);  // true

// Singleton using IIFE
const Database = (function() {
    let instance = null;
    
    function createInstance() {
        return {
            query(sql) {
                console.log(`Executing: ${sql}`);
            }
        };
    }
    
    return {
        getInstance() {
            if (!instance) {
                instance = createInstance();
            }
            return instance;
        }
    };
})();

const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2);  // true

Factory

// Factory function
function createUser(type, data) {
    const baseUser = {
        created: new Date(),
        greet() {
            return `Hello, I'm ${this.name}`;
        }
    };
    
    switch (type) {
        case 'admin':
            return { ...baseUser, ...data, permissions: ['read', 'write', 'delete'] };
        case 'moderator':
            return { ...baseUser, ...data, permissions: ['read', 'write'] };
        case 'user':
            return { ...baseUser, ...data, permissions: ['read'] };
        default:
            throw new Error(`Unknown user type: ${type}`);
    }
}

const admin = createUser('admin', { name: 'Alice', email: 'alice@example.com' });
console.log(admin.permissions);  // ['read', 'write', 'delete']

// Factory using classes
class UserFactory {
    static create(type, data) {
        const baseProps = {
            id: Date.now(),
            createdAt: new Date(),
            type
        };
        
        const typeSpecific = this.getTypeSpecificProps(type);
        
        return { ...baseProps, ...typeSpecific, ...data };
    }
    
    static getTypeSpecificProps(type) {
        const types = {
            premium: { isPremium: true, maxStorage: '100GB' },
            free: { isPremium: false, maxStorage: '5GB' }
        };
        return types[type] || {};
    }
}

Observer

// Simple Event Emitter
class EventEmitter {
    constructor() {
        this.events = {};
    }
    
    on(event, callback) {
        if (!this.events[event]) {
            this.events[event] = [];
        }
        this.events[event].push(callback);
    }
    
    off(event, callback) {
        if (this.events[event]) {
            this.events[event] = this.events[event].filter(cb => cb !== callback);
        }
    }
    
    emit(event, ...args) {
        if (this.events[event]) {
            this.events[event].forEach(callback => callback(...args));
        }
    }
    
    once(event, callback) {
        const wrapper = (...args) => {
            callback(...args);
            this.off(event, wrapper);
        };
        this.on(event, wrapper);
    }
}

// Usage
const emitter = new EventEmitter();

emitter.on('message', (data) => {
    console.log('Listener 1:', data);
});

emitter.on('message', (data) => {
    console.log('Listener 2:', data.toUpperCase());
});

emitter.emit('message', 'Hello World');
// Listener 1: Hello World
// Listener 2: HELLO WORLD

Middleware

// Middleware pattern for request processing
class MiddlewareChain {
    constructor() {
        this.middlewares = [];
    }
    
    use(fn) {
        this.middlewares.push(fn);
    }
    
    async execute(context) {
        let index = 0;
        
        const next = async () => {
            if (index >= this.middlewares.length) {
                return context;
            }
            
            const middleware = this.middlewares[index++];
            await middleware(context, next);
        };
        
        await next();
        return context;
    }
}

// Example middlewares
const logging = async (ctx, next) => {
    console.log(`[${new Date().toISOString()}] ${ctx.method} ${ctx.url}`);
    await next();
    console.log('Response status:', ctx.status);
};

const auth = async (ctx, next) => {
    if (!ctx.user) {
        ctx.status = 401;
        return;
    }
    await next();
};

const validate = async (ctx, next) => {
    if (!ctx.body || Object.keys(ctx.body).length === 0) {
        ctx.status = 400;
        ctx.error = 'Request body required';
        return;
    }
    await next();
};

// Usage
const chain = new MiddlewareChain();
chain.use(logging);
chain.use(auth);
chain.use(validate);

await chain.execute({ method: 'POST', url: '/api/users', user: { id: 1 }, body: { name: 'Alice' } });

Performance Optimization

Debouncing and Throttling

// Debounce - wait for function to stop being called
function debounce(fn, delay) {
    let timeoutId;
    
    return function(...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => fn.apply(this, args), delay);
    };
}

// Example - search input
const handleSearch = debounce((query) => {
    console.log('Searching for:', query);
}, 300);

// User types "hello"
// After 300ms of not typing, logs "Searching for: hello"

// Throttle - limit function execution rate
function throttle(fn, limit) {
    let inThrottle;
    
    return function(...args) {
        if (!inThrottle) {
            fn.apply(this, args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

// Example - scroll handler
const handleScroll = throttle(() => {
    console.log('Scroll position:', window.scrollY);
}, 100);

window.addEventListener('scroll', handleScroll);

Memoization

// Simple memoization
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.apply(this, args);
        cache.set(key, result);
        return result;
    };
}

// Example - expensive calculation
const fibonacci = memoize(function(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
});

console.log(fibonacci(40));  // Fast due to memoization
console.log(fibonacci(40));  // Even faster from cache

Lazy Loading

// Lazy load images
function lazyLoadImages() {
    const images = document.querySelectorAll('img[data-src]');
    
    const observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                img.src = img.dataset.src;
                img.removeAttribute('data-src');
                observer.unobserve(img);
            }
        });
    });
    
    images.forEach(img => observer.observe(img));
}

// Dynamic import
async function loadFeature() {
    if (needsPremiumFeature()) {
        const { premiumFeature } = await import('./premium.js');
        premiumFeature();
    }
}

Memory Management

Garbage Collection

JavaScript automatically cleans up unused memory through garbage collection:

// Objects become eligible for GC when no references exist
let obj = { name: "Alice" };
obj = null;  // Previous object is now eligible for GC

// Closure can prevent GC
function createLeak() {
    const largeData = new Array(10000000);
    
    return function() {
        return largeData.length;
    };
}

const leak = createLeak();  // largeData stays in memory
leak = null;  // Now eligible for GC

Memory Leaks

// Common memory leak - forgotten timers
let data = [];
const interval = setInterval(() => {
    data.push(new Array(1000000));
}, 1000);

// Clear to prevent leak
clearInterval(interval);

// Common leak - detached DOM nodes
const container = document.getElementById('container');
const button = document.createElement('button');
container.appendChild(button);
container.removeChild(button);
// button still in memory if referenced

// Common leak - global event listeners
class Handler {
    constructor() {
        this.data = new Array(1000000);
    }
    
    handleClick() {
        console.log('Clicked');
    }
}

const handler = new Handler();
document.addEventListener('click', handler.handleClick);
// Remove to prevent leak
document.removeEventListener('click', handler.handleClick);

Advanced Array Operations

Typed Arrays

// Int8Array - signed 8-bit integers
const int8 = new Int8Array([1, 2, 127, -128]);
console.log(int8[0]);  // 1
console.log(int8[3]);  // -128

// Uint8Array - unsigned 8-bit integers
const uint8 = new Uint8Array([255, 256]);  // 256 becomes 0
console.log(uint8[0]);  // 255
console.log(uint8[1]);  // 0

// Float32Array - 32-bit floating point
const float32 = new Float32Array([1.5, 2.5]);
console.log(float32[0]);  // 1.5

// Int16Array, Int32Array, Uint16Array, Uint32Array, etc.
const int16 = new Int16Array(100);  // Create array of 100 16-bit integers

// Typed arrays have fixed length
const arr = new Int8Array(3);
arr[0] = 100;
arr[1] = 200;
// arr[2] is 0 by default
// arr[3] would be out of bounds

Array Buffers

// Create buffer
const buffer = new ArrayBuffer(16);
console.log(buffer.byteLength);  // 16

// View the buffer
const view = new DataView(buffer);

// Write values
view.setInt8(0, 127);
view.setInt16(2, 1000, true);  // little-endian
view.setFloat64(4, 3.14159);

// Read values
console.log(view.getInt8(0));        // 127
console.log(view.getInt16(2, true)); // 1000
console.log(view.getFloat64(4));     // 3.14159

Symbol and Iteration

Symbol

// Create unique symbol
const sym1 = Symbol('description');
const sym2 = Symbol('description');
console.log(sym1 === sym2);  // false

// Well-known symbols
// Symbol.iterator - custom iteration
// Symbol.toStringTag - custom toString
// Symbol.hasInstance - custom instanceof

// Custom iterator
const collection = {
    items: [1, 2, 3],
    [Symbol.iterator]() {
        let index = 0;
        return {
            next: () => {
                if (index < this.items.length) {
                    return { value: this.items[index++], done: false };
                }
                return { done: true };
            }
        };
    }
};

for (const item of collection) {
    console.log(item);  // 1, 2, 3
}

Iterators and Generators

// Iterator protocol
const stringIterator = "hello"[Symbol.iterator]();
console.log(stringIterator.next());  // { value: 'h', done: false }
console.log(stringIterator.next());  // { value: 'e', done: false }

// Generator functions
function* numberGenerator() {
    yield 1;
    yield 2;
    yield 3;
}

const gen = numberGenerator();
console.log(gen.next());  // { value: 1, done: false }
console.log(gen.next());  // { value: 2, done: false }
console.log(gen.next());  // { value: 3, done: false }
console.log(gen.next());  // { value: undefined, done: true }

// Generator with parameters
function* fibonacci() {
    let a = 0, b = 1;
    while (true) {
        yield a;
        [a, b] = [b, a + b];
    }
}

const fib = fibonacci();
console.log(fib.next().value);  // 0
console.log(fib.next().value);  // 1
console.log(fib.next().value);  // 1
console.log(fib.next().value);  // 2
console.log(fib.next().value);  // 3

Reflect API

// Reflect - built-in object for metaprogramming

// Create object with prototype
const proto = { greet() { return "Hello"; } };
const obj = Reflect.create(proto);
console.log(obj.greet());  // "Hello"

// Check if property exists
console.log(Reflect.has({ a: 1 }, 'a'));  // true
console.log(Reflect.has({ a: 1 }, 'b'));  // false

// Get/set properties
const target = { a: 1 };
Reflect.set(target, 'b', 2);
console.log(Reflect.get(target, 'b'));  // 2

// Delete property
Reflect.deleteProperty({ a: 1 }, 'a');
console.log(Reflect.has({ a: 1 }, 'a'));  // false

// Apply function
function add(a, b) { return a + b; }
console.log(Reflect.apply(add, null, [2, 3]));  // 5

Proxy API

// Proxy - intercept and customize operations on objects
const handler = {
    get(target, property) {
        console.log(`Getting ${property}`);
        return target[property];
    },
    set(target, property, value) {
        console.log(`Setting ${property} to ${value}`);
        target[property] = value;
        return true;
    }
};

const proxy = new Proxy({}, handler);
proxy.name = "Alice";  // Setting name to Alice
console.log(proxy.name);  // Getting name - Alice

// Validation with Proxy
const validator = {
    set(target, property, value) {
        if (property === 'age') {
            if (typeof value !== 'number' || value < 0 || value > 150) {
                throw new RangeError('Invalid age');
            }
        }
        target[property] = value;
        return true;
    }
};

const person = new Proxy({}, validator);
person.age = 25;  // OK
// person.age = -5;  // RangeError

Summary

Topic Key Concepts
OOP Classes, inheritance, private fields, static methods
Prototypes Prototype chain, Object.create, prototypal inheritance
Closures Function scope, private variables, memory considerations
this Binding, call/apply/bind
Async Event loop, microtasks, macrotasks
Patterns Module, Singleton, Factory, Observer, Middleware
Performance Debouncing, throttling, memoization
Memory Garbage collection, memory leaks
Advanced Arrays Typed arrays, ArrayBuffer
Metaprogramming Symbol, Reflect, Proxy, Generators

Clone this wiki locally