Functions are the most important building block in JavaScript. This guide covers every kind of function you will encounter — declarations, expressions, arrow functions, default parameters, rest parameters, closures, callbacks and higher-order functions — all explained simply with working examples.
Shashank ShekharJanuary 2025 · JavaScript
Almost everything in JavaScript involves functions. You use them to organise your code into reusable pieces, to respond to user events, to transform data and to build entire applications. Understanding functions deeply is not optional — it is the most important skill in JavaScript.
The good news is that JavaScript gives you many different ways to write functions, and each one has a purpose. By the end of this guide you will know exactly which kind to use in any situation, how they each behave, and some powerful patterns like closures and higher-order functions that experienced developers use every day.
Download This Article as a Cheat SheetSave a clean PDF summary of all JavaScript function types, syntax and examples for offline reference.
PDF · 1 page · Free
What Is a Function
A function is a reusable block of code that performs a specific job. You write it once and can run it as many times as you want, from anywhere in your code. You can even give it different inputs each time to get different results.
Think of a function like a recipe. You write the recipe once. Every time you want to cook that dish you follow the same recipe, but you might use different quantities each time — more spice today, less tomorrow. The recipe itself does not change.
In JavaScript, functions are "first-class citizens" — which means you can store them in variables, pass them to other functions as arguments, and return them from other functions. This is what makes JavaScript so flexible and powerful.
Function Declarations
The most traditional way to create a function is with the function keyword followed by a name. This is called a function declaration.
JavaScript — basic function declaration
// Define the functionfunctiongreet(name){return`Hello, ${name}!`;}// Call the functionconsole.log(greet('Shashank'));// Hello, Shashank!console.log(greet('Priya'));// Hello, Priya!// A function with multiple parametersfunctionadd(a,b){returna+b;}console.log(add(3,7));// 10
Hoisting — Call Before You Define
Function declarations are hoisted. This means JavaScript moves them to the top of the current scope before any code runs. So you can actually call a function declaration before the line where you wrote it. This is unique to function declarations.
JavaScript — function declarations are hoisted
// This works even though greet is defined BELOW this lineconsole.log(greet('Shashank'));// Hello, Shashank!functiongreet(name){return`Hello, ${name}!`;}
Function Expressions — Functions as Values
You can also create a function and assign it to a variable. This is called a function expression. The function itself has no name (it is anonymous). The variable name is how you call it.
Function expressions are not hoisted. If you try to call one before the line where it is assigned, you will get an error.
JavaScript — function expressions stored in variables
// Anonymous function expressionconstgreet=function(name){return`Hello, ${name}!`;};console.log(greet('Shashank'));// Hello, Shashank!// Named function expression — the name only exists inside the function itself// Useful for recursion and better stack tracesconstfactorial=functioncalc(n){if(n<=1)return1;returnn*calc(n-1);// uses the internal name 'calc' to recurse};console.log(factorial(5));// 120
Arrow Functions — The Modern Shorthand
Arrow functions are a shorter way to write function expressions, introduced in ES6. They use the => syntax and are now the most common way to write small functions in modern JavaScript code.
JavaScript — arrow function syntax in all its forms
// Full arrow functionconstgreet=(name)=>{return`Hello, ${name}!`;};// Single parameter — parentheses are optionalconstgreet=name=>{return`Hello, ${name}!`;};// Single expression — curly braces and return are optional// The expression is automatically returnedconstgreet=name=>`Hello, ${name}!`;// No parameters — empty parentheses are requiredconstsayHi=()=>'Hi!';// Multiple parameters — parentheses always requiredconstadd=(a,b)=>a+b;// Returning an object — wrap it in parentheses to avoid confusion with a blockconstmakeUser=name=>({name,active:true});console.log(greet('Shashank'));// Hello, Shashank!console.log(add(4,6));// 10console.log(makeUser('Rahul'));// { name: 'Rahul', active: true }
Arrow Functions and this
The most important difference between arrow functions and regular functions is how they handle this. Regular functions create their own this context. Arrow functions do not — they inherit this from the surrounding code. This makes arrow functions very useful inside class methods and event handlers.
JavaScript — this behaves differently in arrow vs regular functions
classTimer{constructor(){this.seconds=0;}startBroken(){// Regular function creates its own 'this' — loses the class referencesetInterval(function(){this.seconds++;// 'this' is undefined here — TypeError!},1000);}startFixed(){// Arrow function inherits 'this' from startFixed — works correctlysetInterval(()=>{this.seconds++;// 'this' is the Timer instanceconsole.log(this.seconds);},1000);}}
ℹ️When to use each: use arrow functions for short callbacks, array methods and anywhere you want to inherit this. Use regular function declarations for top-level named functions that might benefit from hoisting. Both are correct — context matters.
Parameters in Depth
Default Parameters
You can give a parameter a default value. If the caller does not pass that argument (or passes undefined), the default is used automatically.
JavaScript — default parameter values
functiongreet(name='friend',greeting='Hello'){return`${greeting}, ${name}!`;}console.log(greet());// Hello, friend!console.log(greet('Shashank'));// Hello, Shashank!console.log(greet('Priya','Namaste'));// Namaste, Priya!// Default values can even be expressions or other function callsconstcreateId=()=>Math.random().toString(36).slice(2);functioncreateUser(name,id=createId()){return{name,id};}
Rest Parameters — Collect Extra Arguments
The rest parameter ...args collects all remaining arguments into an array. It must always be the last parameter. This is how you write functions that accept any number of arguments.
functionsum(...numbers){returnnumbers.reduce((total,n)=>total+n,0);}console.log(sum(1,2,3));// 6console.log(sum(10,20,30,40,50));// 150// Mix fixed and rest parametersfunctionlogMessage(level,...parts){console.log(`[${level}]`,parts.join(' '));}logMessage('ERROR','Something','went','wrong');// [ERROR] Something went wrong
Destructuring Parameters
Instead of passing a big object and accessing properties inside the function, you can destructure right in the parameter list. This makes function signatures self-documenting.
JavaScript — object destructuring in function parameters
// Without destructuring — verbose, repetitivefunctiondisplayUser(user){console.log(user.name,user.age,user.city);}// With destructuring — clean and self-documentingfunctiondisplayUser({name,age,city}){console.log(name,age,city);}// Combine destructuring with default valuesfunctioncreateButton({text='Click me',color='blue',disabled=false}={}){return`<button style="color:${color}" ${disabled ? 'disabled' : ''}>${text}</button>`;}console.log(createButton());// all defaultsconsole.log(createButton({text:'Submit',color:'green'}));
Return Values
A function sends a value back to the caller using return. As soon as JavaScript hits a return statement, it stops executing the function and sends that value back. Functions that do not have a return statement automatically return undefined.
JavaScript — return values and early returns
// Return stops execution immediatelyfunctiondivide(a,b){if(b===0){returnnull;// early return — exits here if b is zero}returna/b;// only reaches here if b is not zero}console.log(divide(10,2));// 5console.log(divide(10,0));// null — safely handled// Functions can return any value — including objects, arrays or other functionsfunctiongetUser(id){return{id,name:'Shashank',role:'developer'};}
Scope — Where Variables Live
Scope is about visibility — which parts of your code can "see" and use a variable. Variables declared inside a function are local to that function. They are created when the function runs and destroyed when it finishes. Outside code cannot see them.
JavaScript — local scope inside functions
constglobalMessage='I am global';functionshowMessage(){constlocalMessage='I am local';console.log(globalMessage);// works — functions can see global variablesconsole.log(localMessage);// works — inside the function}showMessage();console.log(globalMessage);// worksconsole.log(localMessage);// ReferenceError — localMessage does not exist out here
Closures — Functions That Remember
A closure is a function that remembers the variables from the scope it was created in, even after that outer function has finished running. This sounds confusing but it is one of the most useful and powerful features in JavaScript.
Think of it like a backpack. When a function is created, it gets a backpack containing all the variables from its surrounding scope. Even if the outer function finishes, the inner function still has its backpack and can use those variables.
JavaScript — closures explained with a counter example
functionmakeCounter(){letcount=0;// this variable lives in the closurereturnfunction(){count++;returncount;};}constcounter1=makeCounter();constcounter2=makeCounter();// separate closure, separate countconsole.log(counter1());// 1console.log(counter1());// 2console.log(counter1());// 3console.log(counter2());// 1 — counter2 has its own independent count// Practical use: create a function with locked-in configurationfunctioncreateMultiplier(multiplier){returnn=>n*multiplier;// closes over 'multiplier'}constdouble=createMultiplier(2);consttriple=createMultiplier(3);console.log(double(5));// 10console.log(triple(5));// 15
Higher-Order Functions
A higher-order function is any function that either takes another function as an argument, returns a function, or both. Because JavaScript functions are first-class values, you can pass them around just like numbers or strings.
Higher-order functions are extremely common in JavaScript. Every time you use .map(), .filter(), .forEach() or .reduce() on an array, you are using a higher-order function.
map, filter and reduce
JavaScript — map, filter and reduce explained
constnumbers=[1,2,3,4,5,6,7,8,9,10];// map — transforms every element, returns a NEW array of the same lengthconstdoubled=numbers.map(n=>n*2);console.log(doubled);// [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]// filter — keeps only elements where the function returns trueconstevens=numbers.filter(n=>n%2===0);console.log(evens);// [2, 4, 6, 8, 10]// reduce — collapses the array into a single valueconsttotal=numbers.reduce((sum,n)=>sum+n,0);console.log(total);// 55// Chain them together — filter first, then double, then totalconstsumOfDoubledEvens=numbers.filter(n=>n%2===0)// [2, 4, 6, 8, 10].map(n=>n*2)// [4, 8, 12, 16, 20].reduce((sum,n)=>sum+n,0);// 60console.log(sumOfDoubledEvens);// 60
Callbacks — Passing Functions as Arguments
A callback is a function you pass to another function so it can be called later. Callbacks are everywhere in JavaScript — event listeners, timers, array methods and async operations all use them.
JavaScript — callbacks in different situations
// A function that accepts a callbackfunctionprocessData(data,callback){constresult=data.filter(x=>x>0);callback(result);// call the callback when done}// Pass a named function as the callbackfunctionprintResults(items){console.log('Positive numbers:',items);}processData([-3,1,-1,4,7],printResults);// Or pass an inline arrow function directlyprocessData([-3,1,-1,4,7],items=>console.log(items));// Event listener callbackdocument.getElementById('btn').addEventListener('click',function(){console.log('Button was clicked!');});// setTimeout callback — runs after 2 secondssetTimeout(()=>console.log('2 seconds later!'),2000);
IIFE — Immediately Invoked Function Expression
An IIFE (pronounced "iffy") is a function that runs immediately as soon as it is defined. You wrap the function in parentheses and then add () at the end to call it right away. It is used to create a private scope and avoid polluting the global namespace.
JavaScript — IIFE creates a private scope
// The function is wrapped in () and called immediately with ()(function(){constsecret='only visible inside here';console.log(secret);})();// Arrow function IIFE(()=>{console.log('IIFE with arrow function');})();// IIFE with a parameter(function(name){console.log(`Hello, ${name}!`);})('Shashank');// Hello, Shashank!
Pure Functions — Predictable and Testable
A pure function always returns the same output for the same input and has no side effects (does not modify external data, does not talk to a database, does not change a global variable). Pure functions are easy to test, easy to reason about and behave predictably every time.
JavaScript — pure vs impure functions
// IMPURE — depends on and modifies external statelettotal=0;functionaddToTotal(amount){total+=amount;// modifies external variable — side effectreturntotal;// result depends on external state}// PURE — only uses its inputs, does not touch anything outsidefunctionadd(a,b){returna+b;// always returns a + b. No surprises. No side effects.}// PURE — works with data without modifying the originalfunctionaddItem(cart,item){return[...cart,item];// returns a NEW array, does not mutate 'cart'}constmyCart=['apple','banana'];constnewCart=addItem(myCart,'cherry');console.log(myCart);// ['apple', 'banana'] — unchangedconsole.log(newCart);// ['apple', 'banana', 'cherry']
Quick Reference
Function Type
Syntax
Hoisted
Own this
Best For
Declaration
function name() {}
Yes
Yes
Top-level named functions
Expression
const f = function() {}
No
Yes
Conditionally defined functions
Arrow
const f = () => {}
No
No (inherits)
Callbacks, short functions, classes
IIFE
(function() {})()
No
Yes
Private scope, one-time setup
⚡ Key Takeaways
Function declarations use the function name() {} syntax and are hoisted — you can call them before the line where they are written.
Function expressions store a function in a variable. They are not hoisted. The function itself is usually anonymous.
Arrow functions (() => {}) are shorter and do not have their own this. Single-expression arrows return automatically without needing the return keyword.
Default parameters let you set fallback values that are used when an argument is not passed. Rest parameters (...args) collect unlimited extra arguments into an array.
Destructuring parameters pull named properties directly from an object argument, making function signatures cleaner and self-documenting.
return stops the function immediately and sends a value back. Functions without return give back undefined. Use early returns to handle edge cases at the top of a function.
Variables declared inside a function are local — they cannot be seen from outside. Functions can read outer (global) variables, but outside code cannot see local variables.
A closure is a function that remembers variables from the scope it was created in. Each closure gets its own copy of those variables. This enables patterns like counter factories and function configuration.
Higher-order functions take functions as arguments or return functions. map transforms, filter keeps matching elements, reduce collapses to one value.
A pure function always returns the same output for the same input and has no side effects. Prefer pure functions wherever possible — they are predictable, testable and safe to use anywhere.
📄
Save This Guide as a PDFA one-page cheat sheet covering all JavaScript function types, syntax patterns and key differences. Great for quick reference.