Home

Passing Arguments to JavaScript Function Parameters

Things can be tricky when you want to use a function (with required parameters) as an argument within another function.

The title to this point makes my brain hurt, so let's begin with an example. Say you have a basic JavaScript function that is a simple alias for console.log:

function log(text) {
console.log(text);
}

And you have another function called runFunc that lets you execute some function, which gets passed to runFunc as the only argument.

function runFunc(fn) {
fn();
}

The question is: How can use log() as the argument passed to runFunc()**, given that** log has a required parameter (**text**)?

Calling Functions as Arguments Doesn't Work

JavaScript beginners often start with this pattern, calling log() within runFunc().

runFunc(log("Hello World"));

That's a logical first step, but unfortunately, it doesn't work.

When you use parentheses with a function name, you are calling the function — you're telling the JavaScript runtime to execute the function. What you want to do is define a function to be used with runFunc, so that runFunc simply has a reference to the log function, which it can run at the appropriate time within its code.

Additional Debugging to Uncover the Problem

This problem becomes more elusive to solve because it's not always immediately obvious that there is a problem.

In our case, "Hello World" will still be logged — everything appears to work fine.

But if we also log inside the runFunc method, we can see that log is executed before runFunc.

function log(text) {
console.log(text);
}

function runFunc(fn) {
console.log("Executing runFunc ...");
fn();
}

runFunc(log("Hello World"));

// => "Hello World"
// => "Executing runFunc ..."

Defining Functions as Arguments

Instead, we can define an anonymous function as an argument, and then run log inside that function.

function log(text) {
console.log(text);
}

function runFunc(fn) {
console.log("Executing runFunc ...");
fn();
}

runFunc(function () {
log("Hello World");
});

// => "Executing runFunc ..."
// => "Hello World"

And now we see the results in the correct order!

It's Not the Anonymity

The reason this works is not that the function is anonymous. It's because we didn't run the function, we just defined it.

You could definitely still cause a problem by running the anonymous function, like this:

runFunc(
(function () {
log("Hello World");
})()
); // Notice the extra ()

Likewise, you could also use a named function that they calls the log function.

function logHello() {
log("Hello World");
}

runFunc(logHello);

I don't like this pattern because logHello is so specific that we're unlikely to reuse it elsewhere in the application, which devalues abstracting it into its own function.

A Real-World Example

As a real-world example, see this practice in action when working with addEventListener.

Using Additional Parameters

Although it may not always be an option, when you have control over runFunc, another approach is to add additional parameters to represent arguments that you can pass onto the function within runFunc.

function log(text) {
console.log(text);
}

function runFunc(fn, arg) {
fn(arg);
}

runFunc(log, "Hello World");

Accounting for Multiple Parameters

And you could even use the spread operator to account for multiple arguments being passed to the interior function.

function log(a, b) {
console.log(a, b);
}

function runFunc(fn, ...args) {
fn(...args);
}

runFunc(log, "Hello", "World");

// => "Hello"
// => "World"

Let's Connect

Keep Reading

WTF is Jest?

Learn the basics of the JavaScript testing framework, Jest.

Aug 23, 2021

Compile ES6 Code with Gulp and Babel, Part 5

In the last of the five part series on compiling multiple ES6 files into a minified bundle, you will learn how to add an asset hash to your bundles.

Dec 21, 2018

Generating Workable TypeScript Types from Contentful Content

Automatically generate TypeScript type definitions from a Contentful schema, and then override for front-end adjustments.

May 03, 2023