Por que essa questão incomoda até desenvolvedores experientes?
\nSe você já escreveu em JavaScript, certamente já encontrou ambas as formas de declarar funções. Elas parecem semelhantes, mas se comportam de maneiras completamente diferentes. No Stack Overflow, essa pergunta acumulou milhares de visualizações e dezenas de páginas de discussão. Por quê? Porque a falta de compreensão da diferença entre var functionName = function() {} e function functionName() {} leva a bugs difíceis de detectar.
Hoje vamos entender esse tópico de uma vez por todas. Você aprenderá o que é function declaration e function expression, como funciona o hoisting e quando usar cada abordagem. Vamos lá!
\n\nO que está por trás da sintaxe?
\nVamos começar pelo básico. A primeira opção é a Function Declaration (declaração de função):
\nfunction greet() {\n console.log('Olá!');\n}\nA segunda é a Function Expression (expressão de função):
\nconst greet = function() {\n console.log('Olá!');\n};\nObserve: no primeiro caso, a função tem um nome e está no início da linha. No segundo, atribuímos uma função anônima à variável greet. Mas o mais interessante começa quando vemos como o JavaScript processa essas declarações.
A principal diferença: Hoisting (elevação)
\nHoisting é um mecanismo do JavaScript no qual as declarações de variáveis e funções são movidas para o topo de seu escopo antes da execução do código. Mas ele funciona de forma diferente para declaration e expression.
\n\nFunction Declaration é elevada por completo
\nQuando você usa function functionName() {}, o JavaScript "eleva" toda a declaração da função para o topo. Isso significa que você pode chamar a função antes de ela ser declarada no código:
sayHello(); // "Olá!"\n\nfunction sayHello() {\n console.log('Olá!');\n}\nO código será executado sem erros. Isso é conveniente, mas pode confundir iniciantes.
\n\nFunction Expression não é elevada
\nCom var functionName = function() {} a história é diferente. Apenas a declaração da variável é elevada, mas não o seu valor. A função permanece no lugar:
sayHello(); // TypeError: sayHello is not a function\n\nvar sayHello = function() {\n console.log('Olá!');\n};\nPor que isso acontece? Porque var eleva a declaração da variável sayHello (com o valor undefined), e a atribuição da função ocorre apenas na linha da expressão. Portanto, antes dessa linha, sayHello é undefined, e tentar chamá-lo como função resulta em erro.
A propósito, se você substituir var por let ou const, o erro será diferente — ReferenceError: Cannot access 'sayHello' before initialization. Isso está relacionado ao fato de que let e const não são inicializados até o momento da declaração (a chamada "zona morta temporal").
Escopo: outro ponto de atenção
\nTanto a function declaration quanto a function expression seguem as regras de escopo. Mas há uma nuance.
\n\nFunction Declaration é visível dentro do bloco
\nEmbora a function declaration seja elevada, seu escopo é limitado ao bloco (no modo estrito):
\n'use strict';\nif (true) {\n function greet() {\n console.log('Dentro do bloco');\n }\n greet(); // "Dentro do bloco"\n}\ngreet(); // ReferenceError: greet is not defined (no modo estrito)\nNo modo não estrito, essa declaração "vaza" para fora, mas não é recomendável confiar nisso.
\n\nFunction Expression vive em sua variável
\nCom a function expression, tudo é previsível: a função só está disponível onde a variável está acessível. Se mover