Why does my function call only work when the function is an expression and not when it's a function declaration?

88 Views Asked by At

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?

3

There are 3 best solutions below

0
Robin Zigmond On

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.

2
Nicholas Tower On
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()();
0
Tom O. On

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).