Avatar ·

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

Привет, коллеги! Я начинающий фронтенд-разработчик и столкнулся с путаницей. В разных проектах и учебниках я вижу два способа объявления функций: ```javascript // Способ 1: Function Expression (функциональное выражение) var myFunc = function() { console.log("Hello from expression!"); }; // Способ 2: Function Declaration (объявление функции) function myFunc() { console.log("Hello from declaration!"); } ``` На первый взгляд они делают одно и то же. Но когда я начал писать более сложный код, я заметил странное поведение. Например, если я вызываю функцию до её объявления, то один способ работает, а другой выдаёт ошибку: ```javascript // Это работает sayHello(); // Выведет "Hello!" function sayHello() { console.log("Hello!"); } // А это выдаёт ошибку sayGoodbye(); // TypeError: sayGoodbye is not a function var sayGoodbye = function() { console.log("Goodbye!"); }; ``` Почему так происходит? В чём принципиальная разница между этими двумя способами? Когда лучше использовать один, а когда другой? И есть ли ещё какие-то подводные камни, о которых нужно знать? Заранее спасибо за разъяснения! <<>>

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

Главное отличие между function declaration и function expression заключается в том, как JavaScript обрабатывает их на этапе компиляции. Это называется поднятием (hoisting).

Function Declaration (объявление функции)

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

// Работает! Функция уже доступна благодаря hoisting
sayHello();

function sayHello() {
    console.log("Привет!");
}

JavaScript видит этот код так:

// Функция "поднимается" наверх
function sayHello() {
    console.log("Привет!");
}

// Теперь можем её вызвать
sayHello();

Function Expression (функциональное выражение)

Когда вы используете var myFunc = function() {}, поднимается только объявление переменной var myFunc, но не её значение. Переменная будет undefined до момента присваивания:

// Ошибка! myFunc ещё undefined
sayGoodbye(); // TypeError: sayGoodbye is not a function

var sayGoodbye = function() {
    console.log("Пока!");
};

// Теперь работает
sayGoodbye(); // "Пока!"

JavaScript видит это так:

// Поднимается только объявление переменной
var sayGoodbye;

// Попытка вызова — sayGoodbye === undefined
sayGoodbye(); // Ошибка!

// Присваивание значения
sayGoodbye = function() {
    console.log("Пока!");
};

Когда что использовать?

  • Function Declaration — используйте, когда функция должна быть доступна в любой точке кода (например, для рекурсии, callback-функций или глобальных утилит). Это делает код более читаемым, так как порядок объявления не важен.
  • Function Expression — используйте, когда:
    • Нужно присвоить функцию переменной условно (например, в зависимости от окружения)
    • Функция используется как аргумент (callback)
    • Вы создаёте анонимные функции
    • Нужно контролировать, когда функция становится доступной

Дополнительные отличия

  • Именованные function expression — можно дать имя функции даже в выражении: var myFunc = function namedFunc() {}. Это помогает при отладке (имя появляется в стеке вызовов).
  • Область видимости — function declaration всегда создаётся в текущей области видимости (глобальной или локальной). Function expression может быть присвоена переменной в любой области.
  • Современный синтаксис — в ES6+ часто используют const или let вместо var для function expression: const myFunc = () => {} (стрелочная функция). Это даёт блочную область видимости и предотвращает случайное переопределение.

Пример для наглядности

// Function Declaration — можно вызвать до объявления
result1 = double(5); // 10

function double(x) {
    return x * 2;
}

// Function Expression — вызов до объявления вызовет ошибку
// result2 = triple(5); // TypeError

const triple = function(x) {
    return x * 3;
};

result2 = triple(5); // 15 — теперь работает

В современных проектах (React, Node.js) чаще используют function expression с const и стрелочные функции, так как это даёт больше контроля и предсказуемости. Но function declaration остаётся отличным выбором для "корневых" функций, которые должны быть доступны везде.

<<>>

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

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

1. Условное объявление функций

С function declaration нельзя создать функцию условно — это приведёт к неожиданному поведению:

// Плохо: function declaration в блоке if
if (true) {
    function sayHi() { console.log("Hi"); }
} else {
    function sayHi() { console.log("Bye"); }
}
// В некоторых браузерах сработает последнее объявление!

Правильный подход — использовать function expression:

let sayHi;
if (condition) {
    sayHi = function() { console.log("Hi"); };
} else {
    sayHi = function() { console.log("Bye"); };
}

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

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

const factorial = function fact(n) {
    return n <= 1 ? 1 : n * fact(n - 1);
};
// Имя fact доступно только внутри функции

3. Стрелочные функции (ES6+)

В современном JavaScript стрелочные функции () => {} стали стандартом для function expression. Они короче и не имеют своего this, что упрощает работу в классах и обработчиках событий:

const sum = (a, b) => a + b;
const numbers = [1, 2, 3].map(n => n * 2);

Итог

Для новичков: используйте function declaration для основных функций, которые не зависят от условий. Для всего остального (колбэки, обработчики, модули) — function expression или стрелочные функции. Это сделает код предсказуемым и читаемым.