Skip to main content

Parameters in a callback

Parameters are passed into a callback exactly as into any other function: you simply call the callback with the arguments you need inside the receiving function. You hand over only a reference to the function, and the concrete values are supplied by the code that calls that callback.

Theory

TL;DR

  • The arguments are supplied not by the caller but by the function the callback was given to: callback(data).
  • The parameter names inside the callback are yours; only the order of the arguments matters.
  • To bake in your own values up front, use a closure: doLater(() => greet('Maria')).
  • bind does the same through partial application: greet.bind(null, 'Maria').
  • A callback without parentheses is passed as a reference; parentheses mean an immediate call.

Quick example

javascript
function fetchData(callback) { const data = 'Data from the server'; callback(data); // pass the parameter into the callback } function showData(info) { console.log('Received:', info); } fetchData(showData);

Output:

text
Received: Data from the server

Way 1: calling the callback with arguments inside the function

This is the main route. You pass the callback itself, and the receiving function decides which data to give it and when.

javascript
function processUser(action) { const user = { name: 'Maria' }; action(user); // the receiving function supplies the argument } processUser(user => console.log(`Hello, ${user.name}!`)); // Hello, Maria!

The parameter names inside the callback are arbitrary: info, user, value are just local names. Values are bound by position, so the order matters, not the naming.

javascript
function withPair(callback) { callback(1, 2); } withPair((a, b) => console.log(a, b)); // 1 2 withPair((first, second) => console.log(first, second)); // 1 2

Way 2: a closure, when the arguments must be fixed in advance

Sometimes the receiving function passes you nothing (for example, setTimeout calls the callback with no arguments), yet your own data is needed. Then wrap the call in an arrow function: it closes over the values in its own scope.

javascript
function doLater(callback) { setTimeout(callback, 1000); } doLater(() => console.log('In one second!')); // the wrapper remembers the text
javascript
function greet(name) { console.log(`Hello, ${name}!`); } doLater(() => greet('Oleh')); // correct: the wrapper calls greet later

Way 3: bind and partial application

bind creates a new function with the leading arguments already supplied. The result is convenient to pass as a callback.

javascript
function greet(greeting, name) { console.log(`${greeting}, ${name}!`); } const sayHi = greet.bind(null, 'Hi'); // greeting is fixed doLater(sayHi); // Hi, undefined! because doLater passes nothing const sayHiToMaria = greet.bind(null, 'Hi', 'Maria'); doLater(sayHiToMaria); // Hi, Maria!
TechniqueWhen to use it
callback(data) inside the functionThe data appears inside the receiving function: a request result, an event, an array element
Arrow wrapperYou need to add values of your own or change the order of the arguments
bindYou need partial application, or you need to fix this for an object method

Argument order in common APIs

When a callback goes into a built-in method, the method itself defines the parameter order, and you have to know it.

javascript
[10, 20, 30].map((value, index, array) => value + index); // [10, 21, 32] element.addEventListener('click', event => console.log(event.type)); // event is first // error-first style: the error comes first, then the data loadUser(7, (err, user) => { if (err) { console.error(err.message); return; } console.log(user.name); });

Common mistakes

  • Passing greet('Maria') as the argument instead of a wrapper: the function runs immediately and the receiving function gets undefined.
  • Writing setTimeout(greet('Maria'), 1000) instead of setTimeout(() => greet('Maria'), 1000).
  • Mixing up parameter positions in built-in methods, for example taking index as the first argument of map.
  • Forgetting that the receiving function may call the callback with no arguments at all, in which case every parameter is undefined.
  • Passing an object method as obj.handler and losing this. Use obj.handler.bind(obj) or an arrow wrapper.
  • Relying on arguments inside an arrow function: it has no arguments of its own, use rest parameters (...args).

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.