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')). binddoes 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
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:
Received: Data from the serverWay 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.
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.
function withPair(callback) {
callback(1, 2);
}
withPair((a, b) => console.log(a, b)); // 1 2
withPair((first, second) => console.log(first, second)); // 1 2Way 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.
function doLater(callback) {
setTimeout(callback, 1000);
}
doLater(() => console.log('In one second!')); // the wrapper remembers the textfunction greet(name) {
console.log(`Hello, ${name}!`);
}
doLater(() => greet('Oleh')); // correct: the wrapper calls greet laterWay 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.
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!| Technique | When to use it |
|---|---|
callback(data) inside the function | The data appears inside the receiving function: a request result, an event, an array element |
| Arrow wrapper | You need to add values of your own or change the order of the arguments |
bind | You 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.
[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 getsundefined. - Writing
setTimeout(greet('Maria'), 1000)instead ofsetTimeout(() => greet('Maria'), 1000). - Mixing up parameter positions in built-in methods, for example taking
indexas the first argument ofmap. - 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.handlerand losingthis. Useobj.handler.bind(obj)or an arrow wrapper. - Relying on
argumentsinside an arrow function: it has noargumentsof its own, use rest parameters(...args).
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.