There are three syntactic contexts in which a function can exist:
- As a statement
- As an expression
- As a method definition
The difference between functions as statements and functions as expressions is exemplified by the function expression and the function declaration. The function declaration is quite unique in that it is the only way to declare a function that is technically a statement. To be considered a function declaration, the syntax of function name() {} must reside on its own without being used in the context of an expression. This can be incredibly confusing because you cannot always tell whether a function is a function declaration or function expression based purely on its own syntax; instead, you must look at the context in which it exists:
// This is a statement, and a function declaration:
// And will therefore be hoisted:
function wow() {}
// This is a statement containing a function expression:
const wow = function wow() {};
As we mentioned previously, a function expression is allowed to have a name, just like a function declaration, but that name may not match the name of the variable that the function is assigned to.
It's easiest to think of expressions as anything that can legally exist to the right-hand side of the assignment operator. All of the following right-hand sides are legal expressions:
foo = 123;
foo = [1,2,3];
foo = {1:2,3:4};
foo = 1 | 2 | 3;
foo = function() {};
foo = (function(){})();
foo = [function(){}, ()=>{}, function baz(){}];
Function expressions are as flexible as all the other values in JavaScript in terms of where they can be placed syntactically. Function declarations, as we will discover, are limited. Method definitions are also limited to exist within the confines of either an object literal or a class definition.