Home

JS Функції

Зміст

  1. Оголошення функції
  2. Параметри за замовчуванням
  3. Псевдомасив arguments
  4. Перетворення псевдомасиву (args[])
  5. Функціональний вираз
  6. Колбек-функції
  7. Стрілочні функції
  8. Чисті функції
  9. this Правила визначення
  10. Методи функцій call, apply і bind

Оголошення функції

Починається з ключового слова function, після якого стоїть ім'я - дієслово, що відповідає на запитання «Що зробити?»

function multiply() { code }

Порядок передачі аргументів повинен відповідати порядку оголошених параметрів: значення першого аргументу буде присвоєно першому параметру, другого аргументу - другому параметру тощо. Якщо параметрів буде більше, ніж аргументів, то параметрам без значень буде присвоєно undefined

Оператор return без явно вказаного значення повертає спеціальне значення undefined. За відсутності return в тілі функції, вона все одно поверне undefined

Параметри за замовчуванням

function count(countFrom = 0, countTo = 10, step = 1)

Псевдомасив arguments​

Псевдомасив - колекція з властивістю length і можливістю звернутися до елементу за індексом, але відсутністю більшості методів для роботи з масивом

                    function multiply() {
                        let total = 1;
                        for (const argument of arguments) {
                          total *= argument;
                        }
                        return total;
                      }
                      console.log(multiply(1, 2, 3)); //  6
                      console.log(multiply(1, 2, 3, 4)); //  24
                      console.log(multiply(1, 2, 3, 4, 5)); //  120
                

Перетворення псевдомасиву (args[])

Зазвичай псевдомасив необхідно перетворити у повноцінний масив Використовуючи метод Array.from()

                    function fn() {
                        // Змінна args буде містити повноцінний масив
                        const args = Array.from(arguments);
                    }
                

Використовуючи операцію ... (rest), вона дозволяє зібрати будь-яку кількість елементів, у нашому випадку аргументів, в масив, і зберегти його в змінну.

                    function fn(...args) {
                        // Змінна args буде містити повноцінний масив
                    }
                

Функціональний вираз

Функціональний вираз (function expression) - звичайне оголошення змінної, значенням якої буде функція. Альтернативний спосіб оголошення функції.

                    const multiply = function (x, y, z) {
                        console.log(`Результат множення дорівнює ${x * y * z}`);
                    };
                

Різниця в тому, що функціональний вираз не можна викликати до місця його створення, A оголошення функції можна викликати до місця її створення в коді.

Область видимості (пусто)

Стек викликів (пусто)

Переповнення стека викликів (пусто)

Колбек-функції

Функції не відрізняються від чисел, рядків або масивів - це просто спеціальний тип даних (об'єкт вищого порядку), значення, яке можна зберігати у змінній або передавати у якості аргументу в іншу функцію. Функція зворотного виклику (callback, колбек) - це функція, яка передається іншій функції як аргумент, а та, в свою чергу, викликає передану функцію.

                    // Колбек-функція
                    function greet(name) {
                    console.log(`Ласкаво просимо ${name}.`);
                    }

                    // Функція вищого порядку
                    function registerGuest(name, callback) {
                    console.log(`Реєструємо гостя ${name}.`);
                    callback(name);
                    }

                    registerGuest("Манго", greet);
                

Інлайн колбеки

Якщо колбек-функція - маленька, і потрібна тільки для передачі аргументом, її можна оголосити безпосередньо на момент виклику функції, в яку передаємо колбек. Така функція буде доступна тільки у якості значення параметра і більше ніде в коді.

                    function registerGuest(name, callback) {
                        console.log(`Реєструємо гостя ${name}.`);
                        callback(name);
                      }
                      
                      // Передаємо інлайн функцію greet у якості колбека
                      registerGuest("Манго", function greet(name) {
                        console.log(`Ласкаво просимо ${name}.`);
                      });
                      
                      // Передаємо інлайн функцію notify у якості колбека
                      registerGuest("Полі", function notify(name) {
                        console.log(`Шановний(а) ${name}, ваш номер буде готовий за 30 хвилин.`);
                      });
                

Декілька колбеків

Функція може приймати будь-яку кількість колбеків. Наприклад, уявімо, що ми пишемо логіку прийняття дзвінків для телефону. Програма повинна увімкнути автовідповідач, якщо абонент - недоступний, або з'єднати дзвінок в іншому випадку. Доступність абонента будемо імітувати генератором випадкового числа, щоб між різними викликами функції можна було отримати різні результати.

                    function processCall(recipient) {
                        // Імітуємо доступність абонента випадковим числом
                        const isRecipientAvailable = Math.random() > 0.5;
                      
                        if (!isRecipientAvailable) {
                          console.log(`Абонент ${recipient} недоступний, залиште повідомлення.`);
                          // Логіка активації автовідповідача
                        } else {
                          console.log(`З'єднуємо з ${recipient}, очікуйте...`);
                          // Логіка прийняття дзвінка
                        }
                      }
                      
                      processCall("Манго");
                

Ми могли б написати функцію таким чином, щоб вона повертала якесь значення, і потім за результатом її виконання, робити перевірки і виконувати потрібний код. Але перевірки не стосуються зовнішнього коду і будуть його засмічувати. Виконаємо рефакторинг функції таким чином, щоб вона приймала два колбеки onAvailable і onNotAvailable, і викликала їх за умовою.

                    function processCall(recipient, onAvailable, onNotAvailable) {
                        // Імітуємо доступність абонента випадковим числом
                        const isRecipientAvailable = Math.random() > 0.5;
                      
                        if (!isRecipientAvailable) {
                          onNotAvailable(recipient);
                          return;
                        }
                      
                        onAvailable(recipient);
                      }
                      
                      function takeCall(name) {
                        console.log(`З'єднуємо з ${name}, очікуйте...`);
                        // Логіка прийняття дзвінка
                      }
                      
                      function activateAnsweringMachine(name) {
                        console.log(`Абонент ${name} недоступний, залиште повідомлення.`);
                        // Логіка активації автовідповідача
                      }
                      
                      function leaveHoloMessage(name) {
                        console.log(`Абонент ${name} недоступний, записуємо голограму.`);
                        // Логіка запису голограми
                      }
                      
                      processCall("Манго", takeCall, activateAnsweringMachine);
                      processCall("Полі", takeCall, leaveHoloMessage);
                

Колбеки застосовуються для обробки дій користувача на сторінці, на момент обробки запитів на сервер, виконання заздалегідь невідомих функцій тощо. У цьому і полягає їх суть - це функції, призначені для відкладеного виконання.

Абстракція - приховування деталей реалізації. Дозволяє думати про задачі на вищому (абстрактному) рівні. Функції - це хороший спосіб побудови абстракцій.

                    function printValue(value) {
                        console.log(value);
                      }
                      
                      function prettyPrint(value) {
                        console.log("Logging value: ", value);
                      }
                      
                      function repeat(n, action) {
                        for (let i = 0; i fgh n; i += 1) {
                          action(i);
                        }
                      }
                      
                      // Передаємо printValue як callback-функцію
                      repeat(3, printValue);
                      // 0
                      // 1
                      // 2
                      
                      // Передаємо prettyPrint як callback-функцію
                      repeat(3, prettyPrint);
                      // Logging value: 0
                      // Logging value: 1
                      // Logging value: 2
                

Стрілочні функції

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

Усі стрілки створюються як функціональний вираз, і якщо функція - не анонімна, її необхідно присвоювати змінній.

У них відсутній arguments

                    const foo = (...rest) => {
                        console.log(rest); // [1,5,7,9,4,5]
                    }
                    foo(1,5,7,9,4,5);
                
                    // Звичайне оголошення функції
                    function classicAdd(a, b, c) {
                        return a + b + c;
                    }

                    // Те саме стрілочною функцією
                    const arrowAdd = (a, b, c) => {
                        return a + b + c;
                    };
                

Якщо параметр один, його можна оголошувати без круглих дужок.

                    const add = a => {
                        return a + 5;
                    };
                

Якщо параметри відсутні, то обов'язково повинні бути порожні круглі дужки.

                    const greet = () => {
                        console.log("Привіт!");
                    };

                    супер короткий запис
                    () => {};
                

Існує два варіанти: з фігурними дужками і без них. Якщо є фігурні дужки, і функція повинна повертати якесь значення, необхідно явно поставити return. Це називається явне повернення (explicit return). Такий синтаксис використовується у разі, якщо в тілі функції потрібно виконати ще якісь інструкції, крім повернення значення.

Якщо фігурні дужки відсутні, то повертається результат виразу, який стоїть після =/. Це називається неявне повернення

                    const add = (a, b, c) => a + b + c;
                

доречний тільки тоді, коли в тілі функції не потрібно виконувати жодних додаткових інструкцій, крім повернення значення.

У стрілочних функцій немає локальної змінної arguments.Якщо необхідно зібрати всі аргументи в масив, використовується операція rest

                    const add = (...args) => {
                        console.log(args);
                      };
                      
                      add(1, 2, 3); // [1, 2, 3]
                

Анонімні стрілочні функції відмінно підходять як колбеки для перебираючих методів масиву завдяки коротшому синтаксису оголошення

                    const numbers = [5, 10, 15, 20, 25];

                // Оголошення функції
                numbers.forEach(function (number, index) {
                    console.log(`Індекс ${index}, значення ${number}`);
                });

                // Анонімна стрілочна функція
                numbers.forEach((number, index) => {
                    console.log(`Індекс ${index}, значення ${number}`);
                });
                

Стрілочну колбек-функцію також можна оголошувати окремо і передавати на неї посилання. Це варто робити, якщо одна функція використовується у декількох місцях програми або якщо вона громіздка.

                    const logMessage = (number, index) => {
                        console.log(`Індекс ${index}, значення ${number}`);
                      };
                      
                      numbers.forEach(logMessage);
                

Чисті функції

Функція з побічними ефектами - це функція, яка в процесі виконання може змінювати або використовувати глобальні змінні, змінювати значення аргументів посилального типу, виконувати операції введення-виведення тощо.

Чиста функція (pure function) - це функція, результат якої залежить тільки від значень переданих аргументів. За умови однакових аргументів вона завжди повертає один і той самий результат і не має побічних ефектів, тобто не змінює значення аргументів

Напишемо реалізацію чистої функції множення елементів масиву, що повертає новий масив, не змінюючи вихідний.

                    const pureMultiply = (array, value) => {
                        const newArray = [];
                      
                        array.forEach(element => {
                          newArray.push(element * value);
                        });
                      
                        return newArray;
                      };
                      
                      const numbers = [1, 2, 3, 4, 5];
                      const doubledNumbers = pureMultiply(numbers, 2);
                      
                      // Мутація вихідних даних не відбулася
                      console.log(numbers); // [1, 2, 3, 4, 5]
                      // Функція повернула новий масив зі зміненими даними
                      console.log(doubledNumbers); // [2, 4, 6, 8, 10]
                

this Правила визначення

У глобальній області видимості, якщо скрипт виконується не в суворому режимі, this посилається на об'єкт window. В суворому режимі значення this, в глобальній області видимості, буде undefined.

                    function showThis() {
                        console.log("this in showThis: ", this);
                      }
                      
                      // Викликаємо у глобальному контексті
                      showThis(); // this in showThis: Window
                      
                      const user = {
                        username: "Mango",
                      };
                      
                      // Записуємо посилання на функцію у властивість об'єкта
                      // Зверніть увагу, що це не виклик - немає ()
                      user.showContext = showThis;
                      
                      // Викликаємо функцію в контексті об'єкта
                      // this буде вказувати на поточний об'єкт, в контексті
                      // якого здійснюється виклик, а не на глобальний об'єкт.
                      user.showContext(); // this in showThis: {username: "Mango", showContext: ƒ}
                
                    const customer = {
                        firstName: "Jacob",
                        lastName: "Mercer",
                        getFullName() {
                          return `${this.firstName} ${this.lastName}`;
                        },
                      };
                      
                      function makeMessage(callback) {
                        // callback() - це виклик методу getFullName без об'єкта
                        console.log(`Обробляємо заявку від ${callback()}.`);
                      }
                      
                      makeMessage(customer.getFullName); // Буде помилка у виклику функції
                

this у стрілочних функціях

                    const showThis = () => {
                        console.log("this in showThis: ", this);
                      };
                      
                      showThis(); // this in showThis: window
                      
                      const user = {
                        username: "Mango",
                      };
                      user.showContext = showThis;
                      
                      user.showContext(); // this in showThis: window
                

Методи функцій call, apply і bind

Трапляються ситуації, коли функцію потрібно викликати в контексті об'єкта, при цьому функція не є його методом. Для цього у функцій є методи call, apply і bind.

Метод call()​

                    foo.call(obj, arg1, arg2, ...)
                

Метод call викличе функцію foo таким чином, що в this буде посилання на об'єкт obj, а також передасть аргументи arg1, arg2 тощо.

                    function greetGuest(greeting) {
                        console.log(`${greeting}, ${this.username}.`);
                      }
                      
                      const mango = {
                        username: "Манго",
                      };
                      const poly = {
                        username: "Полі",
                      };
                      
                      greetGuest.call(mango, "Ласкаво просимо"); // Ласкаво просимо, Манго.
                      greetGuest.call(poly, "З прибуттям"); // З прибуттям, Полі
                

Метод apply​

                    foo.apply(obj, [arg1, arg2, ...])
                

Метод apply - це аналог методу call за винятком того, що синтаксис передачі аргументів вимагає не перерахування, а масив, навіть якщо аргумент всього один.

Метод apply викличе функцію foo таким чином, що в this буде посилання на об'єкт obj, а також передасть елементи масиву як окремі аргументи arg1, arg2 тощо.

                    function greetGuest(greeting) {
                        console.log(`${greeting}, ${this.username}.`);
                      }
                      
                      const mango = {
                        username: "Манго",
                      };
                      const poly = {
                        username: "Полі",
                      };
                      
                      greetGuest.apply(mango, ["Ласкаво просимо"]); // Ласкаво просимо, Манго.
                      greetGuest.apply(poly, ["З прибуттям"]); // З прибуттям, Полі.
                

Метод bind()

foo.bind(obj, arg1, arg2, ...)

Методи call і apply викликають функцію «на місці», тобто відразу. Але у разі колбек-функцій, коли необхідно не відразу викликати функцію, а передати посилання на неї, причому з прив'язаним контекстом, використовується метод bind.

Метод bind створює і повертає копію функції foo з прив'язаним контекстом obj і аргументами arg1, arg2 тощо. Утворюється копія функції, яку можна передати куди завгодно і викликати коли завгодно.

function greet(clientName) { return `${clientName}, ласкаво просимо в «${this.service}».`; } const steam = { service: "Steam", }; const steamGreeter = greet.bind(steam); steamGreeter("Манго"); // "Манго, ласкаво просимо в «Steam»." const gmail = { service: "Gmail", }; const gmailGreeter = greet.bind(gmail); gmailGreeter("Полі"); // "Полі, ласкаво просимо в «Gmail»."

bind() і методи об'єкта

У разі передачі методів об'єкта як колбек-функцій, контекст не зберігається. Колбек - це посилання на метод, яка присвоюється як значення параметра, що викликається без об'єкта.

                    const customer = {
                        firstName: "Jacob",
                        lastName: "Mercer",
                        getFullName() {
                          return `${this.firstName} ${this.lastName}`;
                        },
                      };
                      
                      function makeMessage(callback) {
                        // callback() - це виклик методу getFullName без об'єкта
                        console.log(`Обробляємо заявку від ${callback()}.`);
                      }
                      
                      makeMessage(customer.getFullName); // Виникне помилка на момент виклику функції
                

У суворому режимі, значення this в методі getFullName, викликаючи як колбек-функції callback(), буде undefined. Звертаючись до властивостей firstName і lastName, виникне помилка, оскільки undefined - це не об'єкт. Метод bind використовується для прив'язування контексту, передаючи методи об'єкта як колбек-функції. Передамо колбеком не оригінальний метод getFullName, а його копію з прив'язаним контекстом об'єкту customer.

                    // ❌ Було
                    makeMessage(customer.getFullName); // Виникне помилка на момент виклику функції

                    // ✅ Стало
                    makeMessage(customer.getFullName.bind(customer)); // Обробляємо заявку від Jacob Mercer.