I struggled through understanding this as well at first. This is how I reached clarity with it blow for blow. This is my first post on stack and excuse my being long-winded about it.
Let's take a very basic function that returns a string:
function fun() {
return 'Hi!';
}
If we log the above function without the invocation parentheses, the console just logs a reference to the function:
console.log(fun); //logs ---> [Function: fun]
If we log it again, but WITH the invocation parenthesis:
console.log(fun()); //logs ---> Hi!
the invocation of a function is equal to its return value:
console.log(fun() === 'Hi!'); //logs ---> true
So building off of that, let's rewrite our function to have another function declared within it that returns a string. The outer function will return the invocation of the inner function:
function funAgain() {
function innerFun() {
return 'Hello there!';
}
return innerFun();
}
So within the scope of funAgain (innerFun() === 'Hello there!') evaluates to true so when we log an invocation of funAgain to the console:
console.log(funAgain()); //logs ---> 'Hello there!'
But what if we left off the invoking parentheses of innerFun in the return statement of the outer function?
function funAgain() {
function innerFun() {
return 'Hello there!';
}
return innerFun;
}
console.log(funAgain()); //logs [Function: innerFun]
The function ITSELF is returned. Though it's not actually the whole story, we could think of (funAgain() === innerFun) Obviously, you can't actually run this comparison in practice because of scoping issues (innerFun can't exist outside of an invocation of funAgain).
BUT! Let's for a moment think of it that way. That means that if we capture the return value of funAgain in a variable:
var innerFunCaptured = funAgain();
console.log(innerFunCaptured); // logs [Function: innerFun]
We have, again conceptually, (innerFunCaptured === innerFun) ...
So now that our variable is bound to the inner function, we can invoke that inner function by adding parentheses to the variable.
console.log(innerFunCaptured()); //logs ---> 'Hello there!'
When I was talking about the "whole story" above, what I left out was that the inner function's binding to the variable is the result of the outer function's invocation, so really the binding not only includes innerFun itself, but ALSO the environment which it was created within including any potential arguments passed through the invocation of the outer function, which allows us to...
Rewrite the outer and inner function once more so that they now have parameters which interact:
function funOnceMore(greetingPartOne) {
function innerFun(greetingPartTwo) {
return greetingPartOne + ' ' + greetingPartTwo;
}
return innerFun;
}
What if we log funOnceMore with an argument.
console.log(funOnceMore('Hello')) //logs ---> [Function: innerFun]
Again, innerFun itself is returned. But what about the argument greetingPartOne we passed? Well, it was passed alright, but since innerFun was never invoked within funOnceMore, greetingPartOne was never used in any meaningful way. We have to figure out how to invoke innerFun! The answer: we need to bind it to a variable like we did in the previous step.
var innerFunCapturedAgain = funOnceMore('Hello')
Now innerFunCapturedAgain holds innerFun AND the environment of funOnceMore with the argument 'Hello' that we passed into it.
So now we can invoke innerFun by putting parentheses on innerFunCapturedAgain, and those parentheses will encapsulate the argument for greetingPartTwo that we pass to innerFun.
console.log(innerFunCapturedAgain('there!')) //logs ---> 'Hello there!'
doMysteriousThingfunction was created in the variable scope where themakerValuewas passed. This gives that function the ability to referencemakerValueeven though the function is returned and assigned to yourmysteryFunction3. As you can see, it uses it in its return valuereturn makerValue + param;WheremakerValueagain was passed tomakeMysteryFunction(), andparamis passed todoMysteriousThing()newFunction,doMysteriousThingandmysteryFunction3all refer to the same function. To clean it up, I'd get rid of thenewFunctionanddoMysteriousThingnames, and just doreturn function(param) { return makerValue + param; };