Skip to main content

Способи оголошення функцій

У JavaScript функція це значення, тому мова дає одразу кілька синтаксичних форм її створення, від класичного function до стрілок, генераторів і методів класу. Форми відрізняються не лише виглядом: від вибору залежать hoisting, поведінка this, наявність prototype і можливість виклику через new.

Теорія

TL;DR

  • Function declaration піднімається (hoisting), має власний this і може бути конструктором.
  • Function expression доступне лише після присвоєння, буває анонімним або іменованим.
  • Стрілочна функція бере this лексично, не має arguments, prototype і не працює з new.
  • Окремі різновиди: new Function (створення з рядка, не рекомендується), function* (генератор), async function (повертає Promise).
  • Методи об'єктів і класів це також функції, але з підтримкою super через [[HomeObject]].
  • IIFE і bind() це не нові синтаксичні форми, а способи одразу виконати функцію чи зафіксувати її this.

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

javascript
function sum(a, b) { // 1. function declaration return a + b; } const mul = function (a, b) { // 2. function expression return a * b; }; const inc = x => x + 1; // 3. arrow function const obj = { sayHi() { console.log('hi'); } // 4. method shorthand };

Класичні форми: declaration, expression, стрілка

1) Function declaration (оголошення функції)

javascript
function sum(a, b) { return a + b; }
  • Має hoisting: функцію можна викликати до її оголошення в коді.
  • Має власний this при виклику як функції або методу.
  • Можна використовувати як конструктор (new Sum()).

2) Function expression (функціональний вираз)

javascript
const mul = function (a, b) { return a * b; };
  • Hoisting немає: функція доступна лише після присвоєння.
  • Може бути анонімною або іменованою:
javascript
const fact = function factorial(n) { /* ... */ }; // named: the name is visible inside

Ім'я в іменованому виразі видно лише всередині самої функції, і воно зручне для рекурсії та для читабельного стектрейсу.

3) Arrow function (стрілочна функція)

javascript
const inc = x => x + 1; const sum = (a, b) => a + b;
  • Лексичний this: береться з зовнішнього лексичного оточення.
  • Немає arguments (замість нього rest-параметри ...args).
  • Не можна використовувати з new, немає prototype.
  • Чудово підходить для колбеків і коротких функцій.

Спеціальні різновиди: Function, генератори, async

4) Function constructor

javascript
const fn = new Function('a', 'b', 'return a + b');
  • Створює функцію з рядка, так само як eval.
  • Не рекомендується: проблеми з безпекою і продуктивністю, плюс тіло компілюється в глобальній області видимості.

5) Generator function (function*)

javascript
function* idGenerator() { let i = 0; while (true) { yield i++; } }
  • Повертає ітератор і підтримує yield.
  • Виконання можна призупиняти і відновлювати.

6) Async function

javascript
async function fetchData() { const r = await fetch('/api'); return r.json(); } const fn = async () => { /* an async arrow works too */ };
  • Завжди повертає Promise.
  • Усередині можна використовувати await.

Комбінації теж припустимі: async function* це асинхронний генератор для for await...of.

Методи об'єктів і класів

7) Скорочений запис методів в об'єктах

javascript
const obj = { sayHi() { console.log('hi'); }, // method async load() { await fetch('/'); } // async method };
  • Зручно для методів: вони мають [[HomeObject]], тобто підтримку super.
  • Можна писати і як prop: function () {}, але це вже звичайний функціональний вираз без підтримки super.

8) Методи класу (усередині class)

javascript
class C { method() {} static staticMethod() {} async asyncMethod() {} }
  • Оголошення класу не піднімається так, як function declaration: до виконання рядка з class доступу до нього немає.
  • Методи використовують з екземплярами або з самим класом і вони підтримують super.
  • Тіло класу завжди виконується в строгому режимі.

Похідні форми: IIFE та bind

9) IIFE, Immediately Invoked Function Expression

javascript
(function () { // runs immediately })();
  • Корисно для створення локальної області видимості; до появи модулів це був основний спосіб не засмічувати глобальний scope.

10) Function.prototype.bind (створення зв'язаної функції)

javascript
function f() { console.log(this); } const bound = f.bind({ x: 1 });
  • Повертає нову функцію з зафіксованим this та, за потреби, з частково застосованими аргументами.
  • Повторний bind уже зв'язаної функції контекст не змінює.

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

  • Покладатися на hoisting для function expression: mul(2, 3) до рядка з const mul = function ... кине ReferenceError.
  • Оголошувати метод об'єкта стрілкою і чекати, що this вкаже на цей об'єкт.
  • Використовувати new Function чи рядок замість звичайної функції: це той самий ризик, що й eval.
  • Забувати, що async-функція повертає Promise, і читати її результат без await чи .then().
  • Плутати prop: function () {} зі скороченим prop() {}: перший варіант не має [[HomeObject]], тому super у ньому не працює.
  • Оголошувати function declaration усередині блока if і розраховувати на стабільну поведінку в різних середовищах: краще використати вираз.

Порівняння форм

ФормаHoistingВласний thisnewprototype
Function declarationТакТакТакТак
Function expressionНіТакТакТак
Arrow functionНіНі (лексичний)НіНі
new FunctionНіТакТакТак
Generator function*Так (для declaration)ТакНіТак
Async functionТак (для declaration)ТакНіНі
Метод об'єкта або класуНіТакНіНі

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

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

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