0

Learning about closures, I wrote a function that returns a function which prints out a name to the console:

let myName = 'steven';

function printName() {
  console.log(`OUTER: ${myName}`);
  return function printAgain() {
    console.log(`INNER: ${myName}`);
  };
}

printName(); //Only prints 'OUTER: steven'

const newFunc = printName();

newFunc(); //Prints 'OUTER: steven' 
          //AND 'INNER: steven'

Why does the inner function only get called when I have used a function expression? Why does the function declaration only run the outer console log when i call it with printName() and not the second one?

On a similar note, if I call my function expression newFunc without the paranthesis, it only prints OUTER: steven. However, if I use the parenthesis and call it newFunc(), it prints both OUTER: steven AND INNER: steven. Why is that?

Casey Cling
  • 401
  • 2
  • 5
  • 15

3 Answers3

3
newFunc(); //Prints 'OUTER: steven' 
          //AND 'INNER: steven'

Your comments aren't quite right. Here they are fixed:

printName(); //Only prints 'OUTER: steven'

const newFunc = printName(); //Only prints 'OUTER: steven' 

newFunc(); //Only prints 'INNER: steven'

When you call printName(), the outer function runs and hits the first log statement. Then a new function is created, and returned. Nothing will automatically happen with the inner function; that's all dependent on what you do with it afterwards.

In your first example you never do anything with the function that is returned. Since you don't call the returned function, it won't execute and thus won't log anything. In the second example, you do do something with the returned function, saving it to a variable and then calling it. By calling it, you cause it to log the second message

Note: it's not actually important whether you assign the new function to a variable, just that you call it. The following would print out both log statements:

printName()();
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • Thank you so much! Is there a term for that when you use two sets of parenthesis on the end of a function like printName()() in the example above? Is that just bad practice to do it this way? – Casey Cling Jun 16 '20 at 00:25
  • The practice of a function that returns a function is called a "higher order function". I don't know of a term for when you call them both back to back. It's not automatically bad practice, it just depends what your goal is. Often the usefulness from a higher order function is that you can create the inner function and then reuse it multiple times. That can only work if you assign it to a variable. If you don't need that though, then there's no need to do it. – Nicholas Tower Jun 16 '20 at 00:53
0

It seems you are misunderstanding things here. In your example:

function printName() {
  console.log(`OUTER: ${myName}`);
  return function printAgain() {
    console.log(`INNER: ${myName}`);
  };
}

the "outer" function, printName, logs the "OUTER" string whenever it is executed. This execution also happens to return a new function, the "inner" one. This logs the "INNER" string when executed.

So, stepping through the rest of your original code:

printName(); //Only prints 'OUTER: steven'

This executes the outer function, and therefore logs the output you note. It also returns a new function, but as you don't assign this to a variable or otherwise do anything with it, we don't observe that. Note that if you were to execute this returned function, as printName()() for example, you would see the "OUTER" printed, followed by the "INNER".

Which is exactly what you then do, albeit in two stages:

const newFunc = printName();

newFunc(); //Prints 'OUTER: steven' 
          //AND 'INNER: steven'

You have this correct in total effect, but not on what each line is doing. The "OUTER" output comes from const newFunc = printName(), which executes printName. The newFunc() then calls the function returned - the inner function - and therefore logs the "INNER" output.

None of this has anything to do with whether you use function declarations or function expressions, in this case.

Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
0

printName() does 2 things:

1) It console.logs the value of global variable myName.

2) It returns a function named printAgain.

You are calling printName() because you want to assign a value to const newFunc (item 2 mentioned above), but you have to realize that every time you call printName() its console.log is going to be called (item 1 mentioned above).

Tom O.
  • 5,730
  • 2
  • 21
  • 35