Using a function declarations means that you'll deal with function declaration hoisting in which all functions are processed before any code execution so you can technically use them before they are defined, as they are hoisted up to the top, and you won't have block scoping, as they would be function scoped:
foo(); //can be used before declaration appears!
function foo() {
{ //new block
function bar() {
alert(1);
}
}
bar(); //no problem, is function scoped
}
foo(); //alerts 1!
With function expressions, there will be no hoisting and you'll have block scoping if you use let
or const
:
function foo() {
{ //new block
const bar = () => {
alert(1);
}
}
bar(); //ReferenceError: Can't find variable: bar
}
foo();
Finally, using a named function expression allows for the error to provide a named for the function, instead of just an anonymous function for better debugging. Thus: prefer the last choice. It has expected block scoping, (it still has hoisting but it's invalid to access it before declaration in code), and it allows for a better debugging experience.
Also, don't forget that arrow functions do not bind their own this
but take the this
of the enclosing context! Function declarations always have a this
referring to the global object window
or undefined
in strict mode.