Avatar ·

Разница между var functionName = function() {} и function functionName() {} в JavaScript

Всем привет! Я только начал изучать JavaScript и столкнулся с непонятной для меня ситуацией. В разных примерах кода я вижу два способа объявления функций, которые выглядят похоже, но ведут себя по-разному. Первый способ: ```javascript var myFunc = function() { console.log("Привет!"); }; ``` Второй способ: ```javascript function myFunc() { console.log("Привет!"); } ``` На первый взгляд они делают одно и то же — создают функцию с именем `myFunc`. Но я заметил, что если вызвать функцию до её объявления, то первый способ выдаёт ошибку, а второй — работает. Например: ```javascript // Работает test1(); // Выведет "Работает!" function test1() { console.log("Работает!"); } // Ошибка test2(); // TypeError: test2 is not a function var test2 = function() { console.log("Не работает!"); }; ``` Почему так происходит? Есть ли между ними другие различия? Какой способ лучше использовать и в каких случаях? Буду благодарен за подробное объяснение для новичков. <<>>

Основное различие: поднятие (hoisting)

Вы правы, ключевое отличие между этими двумя способами объявления функций — это механизм поднятия (hoisting) в JavaScript. Давайте разберёмся подробнее.

Function Declaration (объявление функции через function имя() {})

Когда вы пишете function myFunc() {}, вы используете Function Declaration. Такие функции полностью "поднимаются" (hoisted) в начало их области видимости. Это означает, что и имя функции, и её тело перемещаются вверх, поэтому вы можете вызывать функцию до её фактического объявления в коде.

// Это работает благодаря hoisting
sayHello(); // "Hello!"

function sayHello() {
    console.log("Hello!");
}

// Интерпретатор видит это так:
// function sayHello() { console.log("Hello!"); }
// sayHello();

Function Expression (функциональное выражение через var/let/const)

Когда вы пишете var myFunc = function() {}, вы создаёте Function Expression. Здесь поднимается только объявление переменной (var), но не присвоенное ей значение. До момента инициализации переменная будет undefined, и попытка вызвать её как функцию приведёт к ошибке.

// Это НЕ работает
tryToCall(); // TypeError: tryToCall is not a function

var tryToCall = function() {
    console.log("Вызвана!");
};

// Интерпретатор видит это так:
// var tryToCall; // поднимается, но значение undefined
// tryToCall(); // undefined() - ошибка!
// tryToCall = function() { console.log("Вызвана!"); };

Другие важные различия

  • Именованные функции: Function Declaration всегда имеет имя. Function Expression может быть анонимным или именованным (для отладки): var myFunc = function namedFunc() {}
  • Область видимости: Function Declaration нельзя использовать внутри блоков if, for и т.д. в строгом режиме. Function Expression — можно.
  • Самовызов (IIFE): Только Function Expression можно использовать для немедленного вызова: (function() { console.log("IIFE"); })();
  • Переопределение: Function Declaration можно переопределить, просто написав новую функцию с тем же именем. С Function Expression вы перезаписываете переменную.

Что и когда использовать?

В современном JavaScript (ES6+) рекомендуется использовать const или let вместо var для Function Expression:

const myFunc = function() { ... };
// или стрелочную функцию:
const myFunc = () => { ... };

Используйте Function Declaration (function name() {}), когда:

  • Функция должна быть доступна во всей области видимости
  • Вы пишете рекурсивные функции (имя функции нужно для самовызова)
  • Код читают другие разработчики, привыкшие к традиционному синтаксису

Используйте Function Expression (const name = function() {}), когда:

  • Функция присваивается переменной условно (например, внутри if)
  • Функция передаётся как аргумент (callback)
  • Вы хотите избежать поднятия для лучшего контроля потока выполнения
  • Вы используете стрелочные функции (они всегда являются выражениями)

Главное правило: выбирайте тот способ, который делает ваш код более читаемым и предсказуемым. Для большинства случаев в современном JavaScript Function Expression с const считается более безопасным и явным выбором.

<<>>

Практические советы и подводные камни

Добавлю несколько практических моментов, которые помогут избежать ошибок.

1. Function Declaration внутри блоков

В нестрогом режиме браузеры по-разному обрабатывают Function Declaration внутри блоков. Лучше так не делать:

// Плохая практика
if (true) {
    function test() { return "A"; }
} else {
    function test() { return "B"; }
}
console.log(test()); // Непредсказуемый результат

2. Рекурсия и именованные Function Expression

Если вам нужна рекурсия в Function Expression, используйте именованное выражение:

const factorial = function calcFactorial(n) {
    return n <= 1 ? 1 : n * calcFactorial(n - 1);
};
// calcFactorial недоступна снаружи, но работает внутри

3. Отладка в DevTools

Именованные Function Expression и Function Declaration отображаются с именем в стеке вызовов, что упрощает отладку. Анонимные функции показываются как (anonymous), что может запутать.

4. Современный стандарт

В ES6+ предпочтение отдаётся const (чтобы избежать случайного переопределения) и стрелочным функциям для коротких выражений. Однако для больших функций или методов класса традиционный синтаксис function name() остаётся актуальным.

Помните: нет "правильного" или "неправильного" способа — есть подходящий для конкретной ситуации. Главное — быть последовательным в рамках одного проекта.