Functions
Functions are reusable blocks of code that perform specific tasks. They allow you to organize code, avoid repetition, and create modular programs.
Function Declaration
Basic Function Declaration
function greet(name) {
return `Hello, ${name}!`;
}
console.log(greet('John')); // 'Hello, John!'
Function Expression
const greet = function(name) {
return `Hello, ${name}!`;
};
console.log(greet('Jane')); // 'Hello, Jane!'
Arrow Functions (ES6)
const greet = (name) => `Hello, ${name}!`;
const add = (a, b) => a + b;
const getUser = () => ({
name: 'John',
age: 30
});
Parameters and Arguments
Default Parameters
function greet(name = 'Guest') {
return `Hello, ${name}!`;
}
console.log(greet()); // 'Hello, Guest!'
console.log(greet('John')); // 'Hello, John!'
Rest Parameters
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
Arguments Object
function oldStyleSum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(oldStyleSum(1, 2, 3)); // 6
Function Scope
Local Scope
function myFunction() {
let localVar = 'I am local';
console.log(localVar); // Works
}
myFunction();
console.log(localVar); // ReferenceError
Global Scope
let globalVar = 'I am global';
function accessGlobal() {
console.log(globalVar); // Works
}
accessGlobal();
Lexical Scope (Closures)
function outerFunction() {
let outerVar = 'I am outer';
function innerFunction() {
console.log(outerVar); // Can access outer scope
}
return innerFunction;
}
const closure = outerFunction();
closure(); // 'I am outer'
Return Statement
Returning Values
function calculateArea(width, height) {
return width * height;
}
let area = calculateArea(10, 5);
console.log(area); // 50
Early Return
function isPositive(number) {
if (number > 0) {
return true;
}
return false;
}
// Or more concisely:
function isPositive(number) {
return number > 0;
}
Returning Multiple Values
function getUserInfo() {
return {
name: 'John',
age: 30,
email: 'john@example.com'
};
}
let user = getUserInfo();
console.log(user.name); // 'John'
Function Types
Anonymous Functions
setTimeout(function() {
console.log('This runs after 1 second');
}, 1000);
Immediately Invoked Function Expressions (IIFE)
(function() {
let privateVar = 'I am private';
console.log(privateVar);
})();
// With arrow function
(() => {
console.log('IIFE with arrow function');
})();
Constructor Functions
function Person(name, age) {
this.name = name;
this.age = age;
this.greet = function() {
return `Hello, my name is ${this.name}`;
};
}
let john = new Person('John', 30);
console.log(john.greet()); // 'Hello, my name is John'
Higher-Order Functions
Functions that take other functions as arguments or return functions:
function calculator(operation, a, b) {
return operation(a, b);
}
function add(a, b) { return a + b; }
function multiply(a, b) { return a * b; }
console.log(calculator(add, 5, 3)); // 8
console.log(calculator(multiply, 5, 3)); // 15
Callback Functions
function fetchData(callback) {
setTimeout(() => {
const data = { name: 'John', age: 30 };
callback(data);
}, 1000);
}
fetchData((user) => {
console.log('User data:', user);
});
Function Methods
call() and apply()
function greet(greeting) {
return `${greeting}, my name is ${this.name}`;
}
let person = { name: 'John' };
console.log(greet.call(person, 'Hello')); // 'Hello, my name is John'
console.log(greet.apply(person, ['Hi'])); // 'Hi, my name is John'
bind()
let person = { name: 'John' };
let greetJohn = greet.bind(person);
console.log(greetJohn('Hello')); // 'Hello, my name is John'
Recursion
Functions that call themselves:
function factorial(n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120
Recursive Array Sum
function sumArray(arr) {
if (arr.length === 0) {
return 0;
}
return arr[0] + sumArray(arr.slice(1));
}
console.log(sumArray([1, 2, 3, 4, 5])); // 15
Pure Functions
Functions that don't have side effects and always return the same result for the same inputs:
// Pure function
function add(a, b) {
return a + b;
}
// Impure function (has side effect)
let total = 0;
function addToTotal(value) {
total += value;
return total;
}
Function Composition
Combining multiple functions:
const compose = (f, g) => (x) => f(g(x));
const add1 = (x) => x + 1;
const multiply2 = (x) => x * 2;
const add1ThenMultiply2 = compose(multiply2, add1);
console.log(add1ThenMultiply2(5)); // 12 ( (5 + 1) * 2 )
Practical Examples
Calculator
function calculator(operation) {
return function(a, b) {
switch(operation) {
case 'add': return a + b;
case 'subtract': return a - b;
case 'multiply': return a * b;
case 'divide': return b !== 0 ? a / b : 'Cannot divide by zero';
default: return 'Invalid operation';
}
};
}
const add = calculator('add');
const multiply = calculator('multiply');
console.log(add(5, 3)); // 8
console.log(multiply(5, 3)); // 15
Debounce Function
function debounce(func, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => func.apply(this, args), delay);
};
}
const debouncedLog = debounce(() => console.log('Debounced!'), 1000);
// This will only log once, 1 second after the last call
debouncedLog();
debouncedLog();
debouncedLog();
Memoization
function memoize(func) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = func.apply(this, args);
cache.set(key, result);
return result;
};
}
const fibonacci = memoize(function(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
});
console.log(fibonacci(10)); // Much faster on subsequent calls
Best Practices
Use Descriptive Names
// Good
function calculateTotalPrice(items, taxRate) {
// ...
}
// Avoid
function calc(items, rate) {
// ...
}
Keep Functions Small
// Good
function validateEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function validatePassword(password) {
return password.length >= 8;
}
// Avoid
function validateUser(user) {
// 50 lines of validation code...
}
Use Arrow Functions Appropriately
// Good for simple expressions
const square = x => x * x;
// Good for callbacks
array.map(item => item * 2);
// Avoid for complex functions
const complexFunction = (a, b, c) => {
// Complex logic here
return result;
};
Handle Errors Properly
function divide(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('Both arguments must be numbers');
}
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
}
Document Functions
/**
* Calculates the area of a rectangle
* @param {number} width - The width of the rectangle
* @param {number} height - The height of the rectangle
* @returns {number} The calculated area
*/
function calculateArea(width, height) {
return width * height;
}
Functions are the building blocks of JavaScript programs. Mastering functions allows you to write clean, modular, and reusable code.
