3

Given the following example:

setTimeout(function name(){console.log(1)}, 1000)  (callback)

Is name() (the callback) considered a function declaration or a named function expression?

I know that function declarations are hoisted and function expressions are not, but because it is within the context of an argument, how would you determine whether you can hoist it or not?

I don't believe it to be a duplicate of what is the difference between function declarations and function expressions.

I'm asking a specific usecase of whether or not named callback functions are function declarations or function expressions. I do not believe this usecase to be covered within the answers provided within that question.

the12
  • 2,395
  • 5
  • 19
  • 37

2 Answers2

5

Generally speaking, if a function definition is in an expression position, then it's a function expression.

When is something an "expression position"? When you cannot put a statement there.

Arguments are expressions (you would not be able to pass an if statement as an argument) therefore function name() {...} is an expression in your example.

And because it is a function expression you could omit the name.


Now you might be wondering about the following: Assuming you know that 5 + 5 is an expression and that you can put 5 + 5 in a line just like so

5 + 5;

it seems we can put expression anywhere we want. So how does JavaScript decide, given

function name() {
  //...
}

whether it is a function declaration or a function expression?

To answer this question we have to look at how the code is structured in general. At the top level, all you have is a list of statements:

<statement1>
<statement2>
<statement3>
...

There are various types of statements, an if statement is one example. There is also the concept of an ExpressionStatement. As the name implies, it's a statement that consists of a single expression. This is the rule that allows you to put 5 + 5; in that list of statements.

But this parsing rule is restricted. It cannot start with the keyword function (among others). Therefore, when JavaScript encounters the above function definition, it won't be parsed as a function expression, because it cannot parse it as an ExpressionStatement. The only choice left is to parse it as a function declaration.


If you are curious about the structure of a JavaScript program you can use https://astexplorer.net (full disclosure: I built this site) to see how popular JavaScript parsers pare the program.

For example,

setTimeout(function name(){console.log(1)}, 1000)

is parsed to

enter image description here

by acorn.

(you should really look at the live version though, because hovering over the AST highlights the corresponding source text, which makes things easier to understand)

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • Wow, that's really impressive. I suppose if I ever need a place on whether a function is an expression or declaration, I know where to look :) – the12 Oct 14 '17 at 01:07
  • Just want to be 100% sure I got it because I was literally thinking about this when I was sleeping lol. Whether a function is an expression or declaration is determined by the position it's in relative to the code, not by the syntax. By position in the code, I mean what code the function is preceded and followed by. i.e.: callback is an expression, and it could only ever be an expression due to its position in the code (as an argument). – the12 Oct 14 '17 at 04:56
  • Yes, if I understand you correctly then you are correct ;) – Felix Kling Oct 14 '17 at 18:24
1

Yes, it is an expression. And the function is callable by its name from within itself.

Try this out:

setTimeout(function name(){
  console.log(1);
  console.log(name);
}, 1000)

Invoke it with a stop-condition though, otherwise you'll run out of stack. Recursions bite...

Igor Soloydenko
  • 11,067
  • 11
  • 47
  • 90
  • just wondering how you know it's an expression, because a function declaration would also by callable by its name. – the12 Oct 14 '17 at 00:09
  • 1
    "In programming, an 'expression' is a combination of values and functions that are combined to create a new value, as opposed to a “statement” which is just a standalone unit of execution and doesn't return anything". A function declaration will actually return the new function. – Sidney Oct 14 '17 at 00:15
  • 1
    @Sidney: It does not *return* a function. A function object is created as a side effect. You can see in the [language spec](https://ecma-international.org/ecma-262/8.0/#sec-function-definitions-runtime-semantics-evaluation) that evaluating a function *declaration* returns nothing. – Felix Kling Oct 14 '17 at 00:21
  • 1
    @FelixKling I'm not sure I understand the distinction. `function name() {}` does return something, right? Does it not return a function? Of course it would actually be an object, since functions are objects in JavaScript. The function also gets hoisted as a side effect. – Sidney Oct 14 '17 at 00:24
  • 1
    @Sidney: In this example it returns a function expression, hence it evaluates to a function. But evaluating a function *declaration* does not *return* anything. I am distinguishing between a function declaration and a function expression. – Felix Kling Oct 14 '17 at 00:26