Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Способи оголошення функцій». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**У JavaScript функцію можна оголосити багатьма способами: function declaration, function expression (анонімне або іменоване), стрілочна функція, конструктор `new Function`, генератор `function*`, `async`-функція, скорочений метод об'єкта, метод класу, IIFE та зв'язана функція через `bind()`.** Відрізняються вони hoisting (підняттям), поведінкою `this`, наявністю `arguments` і `prototype`, можливістю виклику через `new` та підтримкою `super`. ```javascript function sum(a, b) { return a + b; } // declaration, hoisted const mul = function (a, b) { return a * b; }; // expression const inc = x => x + 1; // arrow, lexical this ``` **Ключове:** обирайте форму за потрібною семантикою `this` і за тим, чи має функція бути конструктором, а не за коротшим синтаксисом.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**У 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 | Власний `this` | `new` | `prototype` | | --- | --- | --- | --- | --- | | Function declaration | Так | Так | Так | Так | | Function expression | Ні | Так | Так | Так | | Arrow function | Ні | Ні (лексичний) | Ні | Ні | | `new Function` | Ні | Так | Так | Так | | Generator `function*` | Так (для declaration) | Так | Ні | Так | | Async function | Так (для declaration) | Так | Ні | Ні | | Метод об'єкта або класу | Ні | Так | Ні | Ні |Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.