Deep dive into JavaScript functions, scope, closures, and advanced function concepts.
Deep dive into JavaScript functions, scope, closures, and advanced function concepts.
Learn different ways to define functions in JavaScript and understand when to use each approach
Content by: Dharti Dudhat
MERN Stack Developer
JavaScript provides multiple ways to define functions, each with different characteristics, hoisting behavior, and use cases. Understanding these differences is crucial for writing clean, maintainable code.
// 1. Function Declaration (hoisted)
function greet(name) {
return `Hello, ${name}!`;
}
// 2. Function Expression
const greetUser = function(name) {
return `Hello, ${name}!`;
};
// 3. Arrow Function (ES6+)
const greetArrow = (name) => `Hello, ${name}!`;
// 4. Generator Function
function* numberGenerator() {
yield 1;
yield 2;
yield 3;
}
// 5. Async Function
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
return response.json();
}
// Hoisting demonstration
console.log(greet("John")); // Works - function is hoisted
// console.log(greetUser("Jane")); // Error - not hoisted
// Function expressions with different syntax
const add = function(a, b) {
return a + b;
};
const multiply = (a, b) => a * b;
const divide = (a, b) => {
if (b === 0) {
throw new Error("Division by zero");
}
return a / b;
};
// Immediately Invoked Function Expression (IIFE)
(function() {
console.log("This function runs immediately");
})();
// Modern function patterns (2025)
// Function with default parameters
function createUser(name, email, role = "user", isActive = true) {
return {
name,
email,
role,
isActive,
createdAt: new Date()
};
}
// Function with rest parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
// Function with destructuring
function processUser({ name, email, age = 0 }) {
return `Processing ${name} (${email}) - Age: ${age}`;
}
// Arrow functions with different bodies
const square = x => x * x;
const cube = x => x * x * x;
const processArray = arr => {
const doubled = arr.map(x => x * 2);
const filtered = doubled.filter(x => x > 10);
return filtered.reduce((sum, x) => sum + x, 0);
};
// Generator function example
function* fibonacci() {
let [prev, curr] = [0, 1];
while (true) {
yield curr;
[prev, curr] = [curr, prev + curr];
}
}
// Async function with error handling
async function fetchData(url) {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Fetch error:', error.message);
return null;
}
}
// Function parameters and arguments
// Default parameters
function greet(name = "Guest", greeting = "Hello") {
return `${greeting}, ${name}!`;
}
console.log(greet()); // "Hello, Guest!"
console.log(greet("John")); // "Hello, John!"
console.log(greet("Jane", "Hi")); // "Hi, Jane!"
// Rest parameters
function calculateSum(...numbers) {
return numbers.reduce((sum, num) => sum + num, 0);
}
console.log(calculateSum(1, 2, 3, 4, 5)); // 15
console.log(calculateSum(10, 20)); // 30
// Destructuring parameters
function processUser({ name, email, age = 0, preferences = {} }) {
return {
id: Date.now(),
name,
email,
age,
preferences,
processedAt: new Date()
};
}
const user = {
name: "John Doe",
email: "john@example.com",
age: 30,
preferences: { theme: "dark" }
};
console.log(processUser(user));
// Arguments object (legacy)
function legacyFunction() {
console.log("Number of arguments:", arguments.length);
console.log("Arguments:", Array.from(arguments));
}
legacyFunction(1, 2, 3, "hello");
// Parameter validation
function validateAndProcess(data, options = {}) {
// Validate required parameters
if (!data || typeof data !== 'object') {
throw new Error('Data must be a valid object');
}
if (!data.name || typeof data.name !== 'string') {
throw new Error('Name is required and must be a string');
}
// Process with options
const { validateEmail = true, strictMode = false } = options;
if (validateEmail && data.email) {
const emailRegex = /^[^s@]+@[^s@]+.[^s@]+$/;
if (!emailRegex.test(data.email)) {
throw new Error('Invalid email format');
}
}
if (strictMode && data.age < 0) {
throw new Error('Age cannot be negative');
}
return {
...data,
validated: true,
processedAt: new Date()
};
}
// Function overloading simulation
function processData(data, type = 'default') {
switch (type) {
case 'user':
return processUserData(data);
case 'product':
return processProductData(data);
case 'order':
return processOrderData(data);
default:
return processDefaultData(data);
}
}
function processUserData(data) {
return { ...data, type: 'user', processed: true };
}
function processProductData(data) {
return { ...data, type: 'product', processed: true };
}
function processOrderData(data) {
return { ...data, type: 'order', processed: true };
}
function processDefaultData(data) {
return { ...data, type: 'default', processed: true };
}
// Exercise: Build a Function Library
class FunctionLibrary {
constructor() {
this.functions = new Map();
}
// Register a function
register(name, func, description = '') {
if (typeof func !== 'function') {
throw new Error('Second argument must be a function');
}
this.functions.set(name, {
func,
description,
registeredAt: new Date()
});
console.log(`Function '${name}' registered successfully`);
}
// Execute a registered function
execute(name, ...args) {
const funcData = this.functions.get(name);
if (!funcData) {
throw new Error(`Function '${name}' not found`);
}
try {
const result = funcData.func(...args);
console.log(`Function '${name}' executed successfully`);
return result;
} catch (error) {
console.error(`Error executing function '${name}':`, error.message);
throw error;
}
}
// List all registered functions
list() {
return Array.from(this.functions.entries()).map(([name, data]) => ({
name,
description: data.description,
registeredAt: data.registeredAt
}));
}
// Remove a function
remove(name) {
if (this.functions.delete(name)) {
console.log(`Function '${name}' removed successfully`);
} else {
console.log(`Function '${name}' not found`);
}
}
}
// Exercise: Build a Calculator with Functions
class FunctionCalculator {
constructor() {
this.operations = new Map();
this.history = [];
this.initializeOperations();
}
initializeOperations() {
// Basic arithmetic
this.operations.set('add', (a, b) => a + b);
this.operations.set('subtract', (a, b) => a - b);
this.operations.set('multiply', (a, b) => a * b);
this.operations.set('divide', (a, b) => {
if (b === 0) throw new Error('Division by zero');
return a / b;
});
// Advanced operations
this.operations.set('power', (a, b) => Math.pow(a, b));
this.operations.set('sqrt', (a) => {
if (a < 0) throw new Error('Cannot calculate square root of negative number');
return Math.sqrt(a);
});
this.operations.set('log', (a) => Math.log(a));
// Statistical operations
this.operations.set('average', (...numbers) => {
if (numbers.length === 0) throw new Error('No numbers provided');
return numbers.reduce((sum, num) => sum + num, 0) / numbers.length;
});
this.operations.set('max', (...numbers) => Math.max(...numbers));
this.operations.set('min', (...numbers) => Math.min(...numbers));
}
calculate(operation, ...args) {
const func = this.operations.get(operation);
if (!func) {
throw new Error(`Unknown operation: ${operation}`);
}
try {
const result = func(...args);
this.history.push({
operation,
args,
result,
timestamp: new Date()
});
return result;
} catch (error) {
console.error(`Calculation error: ${error.message}`);
throw error;
}
}
addCustomOperation(name, func) {
if (typeof func !== 'function') {
throw new Error('Second argument must be a function');
}
this.operations.set(name, func);
console.log(`Custom operation '${name}' added successfully`);
}
getHistory() {
return this.history;
}
clearHistory() {
this.history = [];
}
}
// Test the exercises
const lib = new FunctionLibrary();
// Register some functions
lib.register('greet', (name) => `Hello, ${name}!`, 'Greets a person');
lib.register('add', (a, b) => a + b, 'Adds two numbers');
lib.register('multiply', (a, b) => a * b, 'Multiplies two numbers');
// Execute functions
console.log(lib.execute('greet', 'John')); // "Hello, John!"
console.log(lib.execute('add', 5, 3)); // 8
// List registered functions
console.log(lib.list());
const calc = new FunctionCalculator();
// Basic calculations
console.log(calc.calculate('add', 10, 5)); // 15
console.log(calc.calculate('multiply', 4, 3)); // 12
console.log(calc.calculate('power', 2, 8)); // 256
// Statistical calculations
console.log(calc.calculate('average', 1, 2, 3, 4, 5)); // 3
console.log(calc.calculate('max', 10, 5, 20, 15)); // 20
// Add custom operation
calc.addCustomOperation('factorial', (n) => {
if (n < 0) throw new Error('Factorial not defined for negative numbers');
if (n === 0 || n === 1) return 1;
return n * calc.calculate('factorial', n - 1);
});
console.log(calc.calculate('factorial', 5)); // 120
Test your understanding of this topic:
Master JavaScript scope, lexical scoping, closures, and how they work together to create powerful programming patterns
Content by: Harmi Savani
MERN Stack Developer
Scope determines the accessibility of variables and functions in different parts of your code. JavaScript uses lexical scoping, which means the scope is determined by the location of the variable declaration in the source code.
// Global scope
const globalVar = "I'm global";
function testFunction() {
console.log(globalVar); // Accessible
}
// Function scope
function functionScope() {
const functionVar = "I'm in function scope";
console.log(functionVar); // Accessible
function innerFunction() {
console.log(functionVar); // Accessible (closure)
const innerVar = "I'm in inner function";
console.log(innerVar); // Accessible
}
innerFunction();
// console.log(innerVar); // Error - not accessible
}
// Block scope (ES6+)
function blockScope() {
const functionVar = "Function level";
if (true) {
const blockVar = "Block level";
console.log(functionVar); // Accessible
console.log(blockVar); // Accessible
}
console.log(functionVar); // Accessible
// console.log(blockVar); // Error - not accessible
}
// Hoisting and scope
console.log(hoistedVar); // undefined (not an error)
var hoistedVar = "I'm hoisted";
// console.log(notHoisted); // Error
let notHoisted = "I'm not hoisted";
// Temporal dead zone
function temporalDeadZone() {
// console.log(tdzVar); // Error - temporal dead zone
let tdzVar = "I'm in TDZ";
console.log(tdzVar); // Works
}
// Scope chain
const globalVar2 = "Global";
function outerFunction() {
const outerVar = "Outer";
function innerFunction() {
const innerVar = "Inner";
console.log(globalVar2); // Global
console.log(outerVar); // Outer
console.log(innerVar); // Inner
}
innerFunction();
}
// Module scope (ES6 modules)
// In a separate file: utils.js
// export const API_KEY = "secret123";
// export function helper() { return "help"; }
// In main file:
// import { API_KEY, helper } from './utils.js';
// console.log(API_KEY); // Accessible
// console.log(helper()); // Accessible
// Closure fundamentals
function createCounter() {
let count = 0; // Private variable
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
// 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
// Closure with object methods
function createBankAccount(initialBalance) {
let balance = initialBalance;
return {
getBalance() {
return balance;
},
deposit(amount) {
if (amount > 0) {
balance += amount;
return `Deposited ${amount}. New balance: ${balance}`;
}
return "Invalid deposit amount";
},
withdraw(amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
return `Withdrew ${amount}. New balance: ${balance}`;
}
return "Insufficient funds or invalid amount";
}
};
}
const account = createBankAccount(1000);
console.log(account.getBalance()); // 1000
console.log(account.deposit(500)); // "Deposited 500. New balance: 1500"
console.log(account.withdraw(200)); // "Withdrew 200. New balance: 1300"
// Closure with event handlers
function createButtonHandler(buttonId) {
let clickCount = 0;
return function() {
clickCount++;
console.log(`Button ${buttonId} clicked ${clickCount} times`);
if (clickCount === 5) {
console.log(`Button ${buttonId} reached 5 clicks!`);
}
};
}
const button1Handler = createButtonHandler("btn1");
const button2Handler = createButtonHandler("btn2");
// Simulate button clicks
button1Handler(); // "Button btn1 clicked 1 times"
button1Handler(); // "Button btn1 clicked 2 times"
button2Handler(); // "Button btn2 clicked 1 times"
// Closure with async operations
function createDataFetcher(baseUrl) {
let cache = new Map();
return async function(endpoint) {
if (cache.has(endpoint)) {
console.log("Returning cached data");
return cache.get(endpoint);
}
try {
const response = await fetch(`${baseUrl}${endpoint}`);
const data = await response.json();
cache.set(endpoint, data);
console.log("Fetched and cached data");
return data;
} catch (error) {
console.error("Fetch error:", error.message);
return null;
}
};
}
// Closure with configuration
function createConfigurableLogger(level = 'info') {
const levels = { error: 0, warn: 1, info: 2, debug: 3 };
return function(message, messageLevel = 'info') {
if (levels[messageLevel] <= levels[level]) {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] [${messageLevel.toUpperCase()}] ${message}`);
}
};
}
const logger = createConfigurableLogger('warn');
logger('This is info', 'info'); // Won't log
logger('This is a warning', 'warn'); // Will log
logger('This is an error', 'error'); // Will log
// Exercise: Build a Module System with Closures
function createModule(name) {
let privateData = new Map();
let subscribers = new Set();
const module = {
// Public methods
set(key, value) {
privateData.set(key, value);
this.notifySubscribers('set', key, value);
},
get(key) {
return privateData.get(key);
},
delete(key) {
const deleted = privateData.delete(key);
if (deleted) {
this.notifySubscribers('delete', key);
}
return deleted;
},
clear() {
privateData.clear();
this.notifySubscribers('clear');
},
subscribe(callback) {
subscribers.add(callback);
return () => subscribers.delete(callback); // Return unsubscribe function
},
notifySubscribers(action, ...args) {
subscribers.forEach(callback => {
try {
callback(action, ...args);
} catch (error) {
console.error('Subscriber error:', error);
}
});
},
getName() {
return name;
},
getSize() {
return privateData.size;
}
};
return module;
}
// Exercise: Build a State Manager
function createStateManager(initialState = {}) {
let state = { ...initialState };
let listeners = new Set();
let middleware = [];
const stateManager = {
getState() {
return { ...state };
},
setState(newState) {
const oldState = { ...state };
state = { ...state, ...newState };
// Run middleware
middleware.forEach(middlewareFn => {
try {
middlewareFn(oldState, state);
} catch (error) {
console.error('Middleware error:', error);
}
});
// Notify listeners
listeners.forEach(listener => {
try {
listener(state, oldState);
} catch (error) {
console.error('Listener error:', error);
}
});
},
subscribe(listener) {
listeners.add(listener);
return () => listeners.delete(listener);
},
addMiddleware(middlewareFn) {
middleware.push(middlewareFn);
},
reset() {
state = { ...initialState };
listeners.forEach(listener => {
try {
listener(state, {});
} catch (error) {
console.error('Listener error:', error);
}
});
}
};
return stateManager;
}
// Exercise: Build a Function Memoizer
function createMemoizer() {
const cache = new Map();
return function(fn) {
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('Returning cached result');
return cache.get(key);
}
console.log('Computing new result');
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
};
}
// Test the exercises
const userModule = createModule('users');
const unsubscribe = userModule.subscribe((action, ...args) => {
console.log(`Module ${userModule.getName()}: ${action}`, args);
});
userModule.set('john', { name: 'John', age: 30 });
userModule.set('jane', { name: 'Jane', age: 25 });
console.log(userModule.get('john')); // { name: 'John', age: 30 }
userModule.delete('jane');
unsubscribe(); // Stop listening
const store = createStateManager({ count: 0, user: null });
store.addMiddleware((oldState, newState) => {
console.log('State changed:', { old: oldState, new: newState });
});
const unsubscribeStore = store.subscribe((newState, oldState) => {
console.log('State updated:', newState);
});
store.setState({ count: 1 });
store.setState({ user: { name: 'John' } });
unsubscribeStore();
const memoize = createMemoizer();
const expensiveFunction = memoize((n) => {
console.log('Computing...');
return n * n;
});
console.log(expensiveFunction(5)); // Computing... 25
console.log(expensiveFunction(5)); // Returning cached result 25
console.log(expensiveFunction(6)); // Computing... 36
Test your understanding of this topic:
Master the 'this' keyword, understand how it changes in different contexts, and learn modern patterns for handling 'this'
Content by: Umesh Dangar
MERN Stack Developer
The 'this' keyword refers to the object that is currently executing the code. Its value depends on how a function is called, not how it's defined. Understanding 'this' is crucial for object-oriented programming in JavaScript.
// This in global context
console.log(this); // Window (in browser) or global (in Node.js)
// This in function context
function regularFunction() {
console.log(this);
}
regularFunction(); // Window/global (in non-strict mode)
// This in method context
const obj = {
name: 'Object',
method() {
console.log(this.name);
}
};
obj.method(); // "Object"
// This in constructor context
function Person(name) {
this.name = name;
this.greet = function() {
console.log(`Hello, I'm ${this.name}`);
};
}
const person = new Person('John');
person.greet(); // "Hello, I'm John"
// This in arrow function context
const arrowObj = {
name: 'Arrow Object',
regularMethod() {
console.log('Regular method:', this.name);
setTimeout(function() {
console.log('Callback function:', this.name); // undefined
}, 100);
setTimeout(() => {
console.log('Arrow function:', this.name); // "Arrow Object"
}, 200);
}
};
arrowObj.regularMethod();
// This in event handler context
const button = document.createElement('button');
button.textContent = 'Click me';
button.addEventListener('click', function() {
console.log(this); // The button element
});
// This with call, apply, bind
const user = {
name: 'John',
greet(greeting) {
console.log(`${greeting}, ${this.name}!`);
}
};
const admin = {
name: 'Admin'
};
user.greet.call(admin, 'Hello'); // "Hello, Admin!"
user.greet.apply(admin, ['Hi']); // "Hi, Admin!"
const boundGreet = user.greet.bind(admin);
boundGreet('Welcome'); // "Welcome, Admin!"
// This in class context
class User {
constructor(name) {
this.name = name;
}
greet() {
console.log(`Hello, ${this.name}!`);
}
static create(name) {
return new User(name);
}
}
const user1 = new User('Alice');
user1.greet(); // "Hello, Alice!"
// This in module context
// In a module file, 'this' refers to undefined (strict mode)
console.log(this); // undefined
// Common this context patterns
// 1. Method borrowing
const calculator = {
add(a, b) {
return a + b;
},
multiply(a, b) {
return a * b;
}
};
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce(calculator.add, 0);
console.log(sum); // 15
// 2. Partial application with bind
function multiply(a, b) {
return a * b;
}
const double = multiply.bind(null, 2);
const triple = multiply.bind(null, 3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
// 3. Event handler binding
class EventHandler {
constructor() {
this.count = 0;
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.count++;
console.log(`Clicked ${this.count} times`);
}
// Alternative: Arrow function method
handleMouseOver = () => {
console.log(`Mouse over, count: ${this.count}`);
}
}
// 4. Callback context preservation
class DataProcessor {
constructor() {
this.data = [];
}
addItem(item) {
this.data.push(item);
}
processItems() {
// Preserve this context in callbacks
this.data.forEach(function(item) {
console.log('Processing:', item);
}.bind(this));
// Or use arrow function
this.data.forEach(item => {
console.log('Processing:', item);
});
}
}
// 5. Method chaining with this
class ChainableObject {
constructor() {
this.value = 0;
}
add(n) {
this.value += n;
return this; // Return this for chaining
}
multiply(n) {
this.value *= n;
return this;
}
subtract(n) {
this.value -= n;
return this;
}
getValue() {
return this.value;
}
}
const chain = new ChainableObject();
const result = chain.add(5).multiply(2).subtract(3).getValue();
console.log(result); // 7
// 6. Factory functions with this
function createCounter() {
return {
count: 0,
increment() {
this.count++;
return this;
},
decrement() {
this.count--;
return this;
},
getValue() {
return this.count;
}
};
}
const counter = createCounter();
console.log(counter.increment().increment().decrement().getValue()); // 1
// 7. This in async context
class AsyncProcessor {
constructor() {
this.data = [];
}
async addItem(item) {
this.data.push(item);
return this;
}
async process() {
const results = [];
for (let item of this.data) {
const result = await this.processItem(item);
results.push(result);
}
return results;
}
async processItem(item) {
return new Promise(resolve => {
setTimeout(() => {
resolve(`Processed: ${item}`);
}, 100);
});
}
}
// 8. This in generator functions
function* numberGenerator() {
let i = 0;
while (true) {
yield i++;
}
}
const gen = numberGenerator();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
// 9. This in proxy objects
const handler = {
get(target, prop, receiver) {
console.log(`Accessing property: ${prop}`);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log(`Setting property: ${prop} = ${value}`);
return Reflect.set(target, prop, value, receiver);
}
};
const proxy = new Proxy({ name: 'John' }, handler);
console.log(proxy.name); // Logs: "Accessing property: name"
proxy.age = 30; // Logs: "Setting property: age = 30"
// Exercise: Build a Chainable API
class ChainableAPI {
constructor() {
this.operations = [];
this.result = null;
}
select(selector) {
this.operations.push({ type: 'select', selector });
return this;
}
filter(callback) {
this.operations.push({ type: 'filter', callback });
return this;
}
map(callback) {
this.operations.push({ type: 'map', callback });
return this;
}
sort(comparator) {
this.operations.push({ type: 'sort', comparator });
return this;
}
limit(n) {
this.operations.push({ type: 'limit', n });
return this;
}
execute(data) {
let result = [...data];
for (let operation of this.operations) {
switch (operation.type) {
case 'select':
result = result.filter(item =>
Object.keys(operation.selector).every(key =>
item[key] === operation.selector[key]
)
);
break;
case 'filter':
result = result.filter(operation.callback);
break;
case 'map':
result = result.map(operation.callback);
break;
case 'sort':
result = result.sort(operation.comparator);
break;
case 'limit':
result = result.slice(0, operation.n);
break;
}
}
this.result = result;
return this;
}
getResult() {
return this.result;
}
reset() {
this.operations = [];
this.result = null;
return this;
}
}
// Exercise: Build a Method Decorator
function logMethod(target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
console.log(`Calling ${propertyKey} with args:`, args);
const result = originalMethod.apply(this, args);
console.log(`${propertyKey} returned:`, result);
return result;
};
return descriptor;
}
function validateMethod(validator) {
return function(target, propertyKey, descriptor) {
const originalMethod = descriptor.value;
descriptor.value = function(...args) {
if (!validator(...args)) {
throw new Error(`Invalid arguments for ${propertyKey}`);
}
return originalMethod.apply(this, args);
};
return descriptor;
};
}
// Exercise: Build a Context Manager
class ContextManager {
constructor() {
this.contexts = new Map();
this.currentContext = null;
}
createContext(name, data = {}) {
const context = {
name,
data: { ...data },
parent: this.currentContext,
children: new Set()
};
if (this.currentContext) {
this.currentContext.children.add(context);
}
this.contexts.set(name, context);
return context;
}
enterContext(name) {
const context = this.contexts.get(name);
if (!context) {
throw new Error(`Context '${name}' not found`);
}
this.currentContext = context;
return context;
}
exitContext() {
if (this.currentContext) {
this.currentContext = this.currentContext.parent;
}
}
getCurrentContext() {
return this.currentContext;
}
setData(key, value) {
if (this.currentContext) {
this.currentContext.data[key] = value;
}
}
getData(key) {
if (this.currentContext) {
return this.currentContext.data[key];
}
return undefined;
}
}
// Test the exercises
const api = new ChainableAPI();
const data = [
{ id: 1, name: 'John', age: 30 },
{ id: 2, name: 'Jane', age: 25 },
{ id: 3, name: 'Bob', age: 35 },
{ id: 4, name: 'Alice', age: 28 }
];
const result = api
.select({ age: 30 })
.map(item => ({ ...item, status: 'active' }))
.limit(2)
.execute(data)
.getResult();
console.log('API Result:', result);
// Test method decorators
class Calculator {
@logMethod
@validateMethod((a, b) => typeof a === 'number' && typeof b === 'number')
add(a, b) {
return a + b;
}
@logMethod
multiply(a, b) {
return a * b;
}
}
const calc = new Calculator();
console.log(calc.add(5, 3)); // Logs method calls and returns 8
// Test context manager
const contextManager = new ContextManager();
contextManager.createContext('user', { id: 1, name: 'John' });
contextManager.enterContext('user');
contextManager.setData('session', 'active');
console.log('Current context:', contextManager.getCurrentContext().name);
console.log('User data:', contextManager.getData('name'));
Test your understanding of this topic:
Continue your learning journey and master the next set of concepts.
Continue to Module 4