Why does this question torment even experienced developers?
\nIf you've ever written in JavaScript, you've surely encountered both of these ways to declare functions. They look similar, but behave completely differently. On Stack Overflow, this question has gathered thousands of views and dozens of pages of discussion. Why? Because not understanding the difference between var functionName = function() {} and function functionName() {} leads to bugs that are hard to catch.
Today, we will finally and forever sort out this topic. You will learn what function declaration and function expression are, how hoisting works, and when to use which method. Let's go!
\n\nWhat lies behind the syntax?
\nLet's start with the basics. The first option is a Function Declaration:
\nfunction greet() {\n console.log('Hello!');\n}\nThe second is a Function Expression:
\nconst greet = function() {\n console.log('Hello!');\n};\nNotice: in the first case, the function has a name and stands at the beginning of the line. In the second, we assign an anonymous function to the variable greet. But the most interesting part begins when we look at how JavaScript processes these declarations.
The main difference: Hoisting
\nHoisting is a JavaScript mechanism where declarations of variables and functions are moved to the top of their scope before code execution. But it works differently for declarations and expressions.
\n\nFunction Declaration is hoisted entirely
\nWhen you use function functionName() {}, JavaScript "hoists" the entire function declaration to the top. This means you can call the function before it is declared in the code:
sayHello(); // "Hello!"\n\nfunction sayHello() {\n console.log('Hello!');\n}\nThe code will execute without errors. This is convenient, but can be confusing for beginners.
\n\nFunction Expression is not hoisted
\nWith var functionName = function() {}, the story is different. Only the variable declaration is hoisted, not its value. The function stays in place:
sayHello(); // TypeError: sayHello is not a function\n\nvar sayHello = function() {\n console.log('Hello!');\n};\nWhy is that? Because var hoists the declaration of the variable sayHello (with the value undefined), and the assignment of the function happens only on the line with the expression. Therefore, before that line, sayHello is undefined, and attempting to call it as a function results in an error.
By the way, if you replace var with let or const, the error will be different — ReferenceError: Cannot access 'sayHello' before initialization. This is because let and const are not initialized until the moment of declaration (the so-called "temporal dead zone").
Scope: another stumbling block
\nBoth function declaration and function expression follow scope rules. But there is a nuance.
\n\nFunction Declaration is visible within the block
\nAlthough function declaration is hoisted, its scope is limited to the block (in strict mode):
\n'use strict';\nif (true) {\n function greet() {\n console.log('Inside the block');\n }\n greet(); // "Inside the block"\n}\ngreet(); // ReferenceError: greet is not defined (in strict mode)\nIn non-strict mode, such a declaration will "leak" out, but relying on this is not recommended.
\n\nFunction Expression lives in its variable
\nWith function expression, everything is predictable: the function is only accessible where the variable is accessible. If you move