Tem casos em que tanto faz, mas há algumas diferenças.

Primeiramente, vale notar que no primeiro caso vc declarou uma função usando function, e no segundo vc criou uma arrow function (a sintaxe (argumentos) => { etc }). Só isso já faz com que não sejam iguais, pois há várias diferenças entre arrow functions e funções definidas com function: veja aqui e aqui para mais detalhes.


Dito isso, mesmo que vc usasse function expression em vez de uma arrow function:

const somar = function (n1, n2) {
    return n1 + n2;
}

Ainda sim seria diferente.

Por exemplo, sabia que isso aqui funciona?

console.log(somar(1, 2)); // 3

function somar(n1, n2) {
    return n1 + n2;
}

Pois é, eu posso chamar uma função antes dela ser definida. Isso acontece por causa do hoisting, que é basicamente um mecanismo que move as declarações de funções (entre outras coisas, veja o link) para o topo do escopo, antes do código ser executado.

Porém, com arrow function ou com function expression não funciona:

console.log(somar(1, 2)); // erro!

const somar = function (n1, n2) {
    return n1 + n2;
}
console.log(somar(1, 2)); // erro!

const somar = (n1, n2) => {
    return n1 + n2;
}

Ambos os códigos acima dão erro. No Chrome, a mensagem foi:

Uncaught ReferenceError: somar is not defined

E no Node foi:

ReferenceError: Cannot access 'somar' before initialization

Isso porque o que temos aqui é uma declaração de variável (const somar), cujo valor é a função anônima. Mas como estamos tentando usá-la antes da atribuição, dá erro.

Para mais detalhes, veja aqui, aqui e aqui.


Outra diferença é que uma função "normal" pode ser "re-declarada":

function somar(n1, n2) {
    return n1 + n2;
}

function somar(n1, n2) {
    return n1 - n2;
}

console.log(somar(1, 2)); // -1

Ou seja, o que acaba valendo é a última versão dela, por isso o código acima imprime -1 em vez de 3.

Agora se eu fizer isso:

const somar = function (n1, n2) {
    return n1 + n2;
}

somar = function (n1, n2) {
    return n1 - n2;
}

console.log(somar(1, 2));

Aí dá erro na segunda atribuição:

TypeError: Assignment to constant variable

Isso porque a variável foi declarada como const, ou seja, não posso atribuir um novo valor a ela. Claro que se ela tivesse sido declarada com var ou let, aí seria possível alterá-la, mas enfim, esta é outra diferença (e este comportamento seria o mesmo se eu usasse arrow function).

Obrigado pela explicação! Eu tenho uma dúvida referente a isso e acredito que você possa responder. Você precisa criar uma função de soma (igual a que você viu que eu fiz), de que forma você criaria, e por quê?

Tipo, se tivesse que usar a função mais de uma vez, criaria com function expression, ou não?

E se tivesse que usar ela somente uma vez, criaria com arrow function?

Depende do contexto, e também cai muito em preferência pessoal. Tenho visto ultimamente uma tendência de usar *arrow function* pra "tudo". Talvez por isso muita gente, principalmente quem está começando, pense que é o único jeito de declarar funções (ou pior, que é o "certo" ou "melhor"). Sendo que o correto seria entender as diferenças entre as formas de declará-las, os prós e contras de cada uma, e aí decidir de acordo com cada contexto. Não existe uma regra certa, e cada um vai ter a sua. Em geral, se algo vai ser usado várias vezes, eu prefiro uma `function` tradicional. Mas muitas vezes, quando a função é curta, e geralmente usada como *callback*, acabo usando *arrow function* mesmo. Por exemplo: ```javascript var array = [1, 2, 3]; var dobro = array.map(n => n * 2); ``` A função é tão curta e direta que não compensa criar uma `function` só pra isso (na minha opinião). A não ser que eu precisasse de algo que a *arrow function* não tem (as diferenças já foram explicadas [aqui](/Ernane/a-diferenca-entre-funcoes-tradicionais-e-arrow-functions-no-javascript), não é só *syntax sugar*, tem casos em que faz diferença). Mas se a função fosse muito grande, provavelmente eu iria optar por criá-la separadamente, para deixar o código mais claro (mesmo que ela seja usada apenas uma vez): ```javascript // Em vez disso: array.map(n => { // 100 linhas de código }); // Eu ia preferir isso: function fazAlgo(n) { // 100 linhas de código } array.map(fazAlgo); ``` O mesmo vale para quando temos uma função que dentro dela tem outra função, que tem outra, etc: ```javascript fazAlgo(function() { // várias linhas de código... ... // função outraCoisa recebe outra função outraCoisa(function() { // várias linhas de código ... // outra função que recebe uma função eMaisOutraCoisa(function() { // várias linhas de código }); }); }); ``` Neste caso, talvez eu declarasse cada função separadamente, em vez de criá-las todas de uma vez em um grande emaranhado - potencialmente confuso - de código. --- Outro caso, suponha que tenho uma função que muda a aparência de um elemento HTML: ```javascript function mudaAparencia(elemento, corFundo, fonte, borda, margem) { // muda o estilo do elemento elemento.style.backgroundColor = corFundo; // etc... } ``` E temos um botão que ao ser clicado, muda para valores específicos: ```javascript button.addEventListener('click', () => mudaAparencia(div, 'red', 'Arial', '4px', '0 auto')); ``` Neste caso uma *arrow function* que chama a função com valores específicos é uma solução simples e rápida. Até daria para fazer algo como: ```javascript function mudaRedArial() { mudaAparencia(div, 'red', 'Arial', '4px', '0 auto'); } button.addEventListener('click', mudaRedArial); ``` Mas a princípio não compensa criar esta função extra (porém, acho que compensaria se ela fosse reutilizada várias vezes). --- Enfim, não tem regra absoluta que serve para todos os casos. Se perguntar para outras pessoas, provavelmente elas terão opiniões diferentes.
Na prática, considerando esses detalhes que o colega comentou acima, você usa a que você achar melhor, porque faz pouquíssima diferença. Eu não sei se existe algum caso de uso em que só dá pra usar uma dessas opções, acredito que não. Eu uso exclusivamente *arrow functions*, até porque são _syntactic sugar_, ou seja, feitas pra facilitar a vida do programador. Quando você vai declarar uma função que só vai ser usada naquele caso específico, como como parâmetro de outra função, por exemplo, é bem mais prático e fácil de ler. Se você trabalha com React ou alguma outra biblioteca ou framework que são muito focadas em programação funcional, *arrow functions* acabam sendo basicamente o padrão. O único caso de diferença *real* é em [funções geradoras](https://javascript.info/generators). Nesse caso, você *precisa* usar a palavra-chave `function*` com o asterisco depois. Não existe equivalente pra *arrow functions*. Mas funções geradoras cumprem objetivos bem específicos e são bem raras.