Одно ли и то же эти куски кода?
Представим что эти ваши фрагменты не в начале кода, а где-нибудь в середине.

В варианте №3 функция будет создана в самом начале, до выполнения самой первой строки. Вызывать ее можно в любом месте.

В вариантах №1 и №2 это не совсем функции, но "функциональные выражения". Они будут обработаны только когда до них дойдет интерпретатор, и  попытка вызвать такую функцию раньше ее объявления приведет к ошибке.

В варианты №1 и  №2 отличаются еще и тем, что одно из выражений анонимное. Ничего плохого в этом нет, но если у функции есть название, то намного удобнее читать код при отладке. В сообщении с ошибкой будет не только номер строки, но и название.


1 - function expression
Функция будет анонимная (без имени), что затруднит отладку, а так же не позволит делать рекурсивные вызовы.
var всплывет наверх функции в которой была объявлена (оборачивающей), но до присваивания будет иметь значение undefined, вызов приведет к ошибке.
Данный тип функций вообще не должен использоваться в нормальном коде.
Функцию можно переопределить в последствии

2 - named function expression
Похоже на предыдущее, но имеет имя, что упрощает отладку и позволяет делать рекурсивные вызовы. В остальном все тоже самое.
Вот так в переменную опять же присваивать не стоит, для дебага хватит стрелочной функции присвоенной в константу (в дебаггере примет имя константы). Но рационально использовать для колбэков, где нужна рекурсия или опять же для удобного дебага.

3. function declaration
Всегда должна иметь имя. Всплывает на верх (можно вызывать до объявления). Нельзя переопределить внутри той же функции (всегда будет вариант, тот что объявлен ниже).

Добавлю еще 4 - arrow function expressionconst func = () => {};на сегодня лучше использовать его вместо function expression