Різниця між 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, для колбеків, обробників та частин виразів.
Швидкий приклад
// --- Function Declaration ---
sayHi(); // працює
function sayHi() {
console.log('Hi!');
}
// --- Function Expression ---
sayBye(); // помилка: змінна ще не ініціалізована
const sayBye = function () {
console.log('Bye!');
};Function declaration
Оголошення функції записується ключовим словом function на початку інструкції:
function sayHello() {
console.log('Hello!');
}Особливості:
- Hoisting. Функція доступна до місця свого оголошення: рушій створює її ще на етапі ініціалізації області видимості, разом із тілом.
- Ім'я функції фіксоване і доступне в поточній області видимості.
- Викликати можна в будь-якому місці файлу чи блоку, навіть вище коду оголошення.
greet(); // працює, хоча функція оголошена нижче
function greet() {
console.log('Hello!');
}Результат:
Hello!Function expression
Функціональний вираз, це функція в правій частині виразу, найчастіше присвоєння:
const sayHello = function () {
console.log('Hello!');
};або стрілкова версія:
const sayHello = () => console.log('Hello!');Особливості:
- Не піднімається як оголошення. Змінна створюється, але функція в ній недоступна до ініціалізації.
- Може бути анонімною (без імені) або іменованою (
const f = function inner() {}, ім'яinnerвидно тільки всередині самої функції і зручне у стеку викликів). - Це вираз, тому викликати функцію можна тільки після присвоєння.
sayHello(); // помилка: до присвоєння функції ще немає
const sayHello = function () {
console.log('Hello!');
};Ключові відмінності
| Властивість | Function Declaration | Function 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 двічі. Пізніше оголошення мовчки перекриває попереднє, і помилка виявиться лише під час виконання.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.