Skip to main content

Різниця між function declaration і function expression

Function declaration оголошує функцію заздалегідь, тому вона доступна в усій своїй області видимості, навіть вище рядка оголошення, а function expression створює функцію лише тоді, коли виконається рядок із присвоєнням. В обох випадках виходить звичайна функція, різниця тільки в тому, у який момент вона з'являється у scope і чи обов'язково має ім'я.

Теорія

TL;DR

  • function greet() {} це declaration: піднімається (hoisting) разом із тілом, викликати можна в будь-якому місці свого scope.
  • const greet = function () {} це expression: піднімається лише змінна, сама функція з'являється після присвоєння.
  • Виклик expression до присвоєння дає ReferenceError для const і let (temporal dead zone) або TypeError: greet is not a function для var.
  • Declaration завжди іменована, expression може бути анонімною або іменованою.
  • Declaration беруть для основних функцій модуля, expression і arrow function, для колбеків, обробників та частин виразів.

Швидкий приклад

javascript
// --- Function Declaration --- sayHi(); // працює function sayHi() { console.log('Hi!'); } // --- Function Expression --- sayBye(); // помилка: змінна ще не ініціалізована const sayBye = function () { console.log('Bye!'); };

Function declaration

Оголошення функції записується ключовим словом function на початку інструкції:

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

Особливості:

  • Hoisting. Функція доступна до місця свого оголошення: рушій створює її ще на етапі ініціалізації області видимості, разом із тілом.
  • Ім'я функції фіксоване і доступне в поточній області видимості.
  • Викликати можна в будь-якому місці файлу чи блоку, навіть вище коду оголошення.
javascript
greet(); // працює, хоча функція оголошена нижче function greet() { console.log('Hello!'); }

Результат:

javascript
Hello!

Function expression

Функціональний вираз, це функція в правій частині виразу, найчастіше присвоєння:

javascript
const sayHello = function () { console.log('Hello!'); };

або стрілкова версія:

javascript
const sayHello = () => console.log('Hello!');

Особливості:

  • Не піднімається як оголошення. Змінна створюється, але функція в ній недоступна до ініціалізації.
  • Може бути анонімною (без імені) або іменованою (const f = function inner() {}, ім'я inner видно тільки всередині самої функції і зручне у стеку викликів).
  • Це вираз, тому викликати функцію можна тільки після присвоєння.
javascript
sayHello(); // помилка: до присвоєння функції ще немає const sayHello = function () { console.log('Hello!'); };

Ключові відмінності

ВластивістьFunction DeclarationFunction Expression
Hoisting (підняття)Так, доступна до оголошенняНі, недоступна до присвоєння
Коли створюєтьсяПри ініціалізації області видимостіПід час виконання рядка
Чи можна викликати до оголошення?ТакНі
Ім'я функціїОбов'язкове, декларація завжди іменованаМоже бути анонімною або іменованою
Підходить дляОсновних функцій, потрібних усюдиЛокальних, переданих як аргумент, колбеків
Приклад використанняfunction sum(a, b) {}const sum = (a, b) => {}

Що обирати

  • Function declaration, коли функція потрібна широко в модулі і її зручно викликати в будь-якому місці, наприклад допоміжні функції верхнього рівня.
  • Function expression або arrow function, коли функція потрібна локально: як обробник події, колбек, аргумент map/filter, частина виразу або значення, яке повертають з іншої функції.

Коротко запам'ятати:

function declaration створюється заздалегідь (hoisting). function expression створюється в момент виконання.

Типові помилки

  • Думати, що expression теж піднімається. Піднімається лише оголошення змінної. З var вона дорівнює undefined, тому виклик дає TypeError: sayBye is not a function; з const і let змінна перебуває в temporal dead zone, тому виклик дає ReferenceError: Cannot access 'sayBye' before initialization.
  • Покладатися на hoisting declaration усередині блоку. У строгому режимі оголошення функції всередині if або циклу обмежене блоком, і поза цим блоком функції не існує.
  • Робити колбеки анонімними без потреби. Іменований вираз (const handler = function handler() {}) дає осмислений стек викликів під час налагодження.
  • Плутати arrow function з експресією function. Arrow function теж є виразом, але не має власного this, arguments і не може бути конструктором.
  • Оголошувати одну й ту саму declaration двічі. Пізніше оголошення мовчки перекриває попереднє, і помилка виявиться лише під час виконання.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.