What does "return function()" inside of a function do?

Hello everyone,
I have here a simple function that should be executed when a button is pressed. It should take the text from an input field and then do something with it (as an example here giving it back as an alert).

function message(id) {
  return function() {  
  let str = document.getElementById(id).value;
  
  alert("message: " + str); 
  };
}

document.getElementById("submit").onclick = message("input-text");

This code works, but there’s something I don’t understand: Why do I need the “return function()” on the second line? Without it, the function executes directly when loading the page. But why? It should be executed on click, shouldn’t it? But clicking the button does nothing anymore without the “return function()” part.

Can someone please explain to me what is happening behind the scenes here?

when you define document.getElementById("submit").onclick =

The code says what is message("input-text") ? so it runs it to try and find out what it should be.

When you add return function() … it is set to a function.

… i should note, this is bad/old code in. and ES6 is a better route:

let message = (id) => {
  let str = document.getElementById(id).value; // ? id always  = "input-text"? or id.target.value ???
  alert("message: " + str); 
}

document.getElementById("submit").onclick = message; // shouldn't auto run
//document.getElementById("submit").onclick = message(); // should auto run

Normally you just pass the function to the click handler as a callback.

document.getElementById("submit").onclick = message;

But because you want to pass an argument (the string to use in getElementById) to it you call the function and pass the argument.

document.getElementById("submit").onclick = message("input-text");

Because you are calling the function it runs. So making it return a function gives you both. You are running a function so it can take an argument and it is returning a function to be used as a callback. The return callback function has a Closure on the argument so it has access to it at a later time when it is invoked.

If you don’t need the argument and always grabbed the same input element you can just move the “input-text” string into the message function and not return anything.

function message() {
  let str = document.getElementById("input-text").value;
  alert("message: " + str); 
}

document.getElementById("submit").onclick = message;

@pjonp
@lasjorg
Thank you for your explanations!

I see that it makes sense to include the id into the function as it stays always the same. Thank you for that!

But I still don’t understand why it can auto run when it’s an onclick event?

There are two functions an outer and an inner. The outer function message is called immediately when the program first runs because it is invoked using parentheses. It does not wait to be called by the on click handler and it only runs one time.

When it runs it returns the inner function to the on click handler and that function does only runs when the on click handler fires.

function message(id) {
  return function() {  
  let str = document.getElementById(id).value;
  
  alert("message: " + str); 
  };
}

const returnFunction = message("input-text");
console.log(returnFunction)
/*
ƒ () {  
  let str = document.getElementById(id).value;
  
  alert("message: " + str); 
  }
*/

So when the outer function runs, it is as if you had done this.

document.getElementById("submit").onclick = function() {
  let str = document.getElementById(id).value;
  alert("message: " + str);
};

However doing that, the callback function will not have access to the id parameter. For the inner function to have access to the id it must be passed to the outer function when it is called. The inner function will then “close over it”, i.e. a Closure. Now, whenever the on click handler fires it will run the inner function and that function still has access to the id because of Closure.

Thank you very much for your answer! I think I got it now :slight_smile: