Return в javascript як працює. Виразний JavaScript: Функції. Локальні та глобальні змінні

💖 Подобається?Поділися з друзями посиланням

Оператори переходу та обробка винятків

Ще однією категорією операторів JavaScript є оператори переходу. Як випливає із назви, ці оператори змушують інтерпретатор JavaScript переходити в інше місце у програмному коді. Оператор break змушує інтерпретатор перейти до кінця циклу чи іншої інструкції. Оператор continue змушує інтерпретатор пропустити частину тіла циклу, що залишилася, перейти назад в початок циклу і приступити до виконання нової ітерації. У мові JavaScript є можливість позначати інструкції іменами, завдяки чому в операторах break і continue можна явно вказувати, до якого циклу чи якоїсь інструкції вони належать.

Оператор return змушує інтерпретатор перейти із викликаної функції назад у точку її виклику та повернути значення виклику. Оператор throw збуджує виняток та призначений для роботи у поєднанні з операторами try/catch/finally, які визначають блок програмного кодудля обробки виняток. Це досить складний різновид операторів переходу: при появі виключення інтерпретатор переходить до найближчого об'ємного оброблювача винятків, який може перебувати в тій же функції або вище, у стеку повернення викликаної функції.

Докладніше всі ці оператори переходу описуються в наступних підрозділах.

Мітки інструкцій

Будь-яка інструкція може бути позначена вказаним перед нею ідентифікатором та двокрапкою:

ідентифікатор: інструкція

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

Надавши ім'я циклу, його потім можна використовувати в інструкціях break і continue, всередині циклу для виходу з нього або для початку циклу, до наступної ітерації. Інструкції break і continue є єдиними інструкціями у мові JavaScript, в яких можна вказувати мітки – про них докладніше розповідається далі. Нижче наведено приклад інструкції while з міткою та інструкції continue, яка використовує цю мітку:

Mainloop: while (token != null) ( // Програмний код опущений... continue mainloop; // Перехід до наступної ітерації іменованого циклу )

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

Мітки інструкцій визначені лише всередині інструкцій, до яких вони застосовуються (і, звичайно ж, всередині інструкцій, що вкладені в них). Вкладені інструкції не можуть позначатися тими ж ідентифікаторами, що і інструкції, що вміщують їх, але дві незалежні інструкції можуть позначатися однаковими мітками. Позначені вказівки можуть позначатися повторно. Тобто будь-яка інструкція може мати безліч міток.

Оператор break

Оператор break призводить до негайного виходу з внутрішнього циклу або оператора switch. Раніше ми вже бачили приклади використання оператора break усередині оператора switch. У циклах він зазвичай використовується для негайного виходу з циклу, коли з якихось причин потрібно завершити виконання циклу.

Коли цикл має дуже складну умову завершення, найчастіше простіше реалізувати ці умови з допомогою оператора break, ніж намагатися висловити в одному умовному вираженні циклу. Наступний приклад намагається знайти елемент масиву з певним значенням. Цикл завершується звичайним чином після досягнення кінця масиву або за допомогою оператора break, як тільки буде знайдено потрібне значення:

Var arr = ["а", "б", "в", "г", "д"], result; for (var i = 0; i

У мові JavaScript допускається вказувати ім'я мітки за ключовим словом break (ідентифікатор без двокрапки):

break имя_метки;

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

Між ключовим словом break та ім'ям мітки не дозволяється вставляти символ перекладу рядка. Справа в тому, що інтерпретатор JavaScript автоматично вставляє пропущені точки з комою: якщо розбити рядок програмного коду між ключовим словом break і наступною за ним міткою, інтерпретатор припустить, що мала на увазі проста форма цього оператора без мітки, і додасть крапку з комою.

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

Оператор continue

Оператор continue схожий на оператора break. Однак замість виходу із циклу оператор continue запускає нову ітерацію циклу. Синтаксис оператора continue так само простий, як і синтаксис оператора break. Оператор continue також може використовуватися з міткою.

Оператор continue як у формі без мітки, так і з міткою може використовуватися тільки в тілі циклу. Використання його в будь-яких інших місцях призводить до синтаксичної помилки. Коли виконується оператор continue, поточна ітерація циклу припиняється і починається наступна. Для різних типівциклів це означає різне:

    У циклі while вказаний на початку циклу вираз перевіряється знову, і якщо воно дорівнює true, тіло циклу виконується з початку.

    У циклі do/while відбувається перехід до кінця циклу, де перед повторним виконанням циклу знову перевіряється умова.

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

    У циклі for/in цикл починається наново із присвоєнням зазначеної змінної імені наступної властивості.

Зверніть увагу на відмінності у поведінці оператора continue у циклах while та for. Цикл while повертається безпосередньо до своєї умови, а цикл forспочатку обчислює вираз інкременту, а потім повертається до умови. У наступному прикладі показано використання оператора continue без мітки для виходу з поточної ітерації циклу для парних чисел:

Var sum = 0; // Обчислити суму парних чисел від 0 - 10 for (var i = 0; i

Оператор continue, як і break, може застосовуватися у вкладених циклах у формі, що включає мітку, і тоді циклом, що заново запускається, необов'язково буде цикл, що безпосередньо містить оператор continue. Крім того, як і для break, переклади рядків між ключовим словом continue та ім'ям мітки не допускаються.

Оператор return

Виклик функції є виразом і подібно до всіх виразів має значення. Оператор return всередині функцій служить визначення значення, повертаного функцією. Оператор return може розташовуватися лише у тілі функції. Присутність його у будь-якому іншому місці є синтаксичною помилкою. Коли виконується оператор return, функція повертає значення виразу програмі, що викликає. Наприклад:

Якщо функція не має оператора return, при її викликі інтерпретатор виконуватиме інструкції в тілі функції одну за одною, поки не досягне кінця функції, і потім поверне керування програмою, що викликала її. У цьому випадку вираз виклику поверне значення undefined. Оператор return часто є останньою інструкцієюу функції, але це зовсім необов'язково: функція поверне керування викликаючою програмою, як тільки буде досягнуто оператора return, навіть якщо за ним слідують інші інструкції в тілі функції.

Оператор return може також використовуватися без виразу, тоді вона просто перериває виконання функції і повертає значення undefined зухвалої програми. Наприклад:

Function myFun(arr) ( // Якщо масив містить запереч. числа, перервати функцію for (var i = 0; i

Оператор throw

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

У JavaScript виняткизбуджуються у випадках, коли виникає помилка часу виконання і коли програма явно збуджує його з допомогою оператора throw. Винятки перехоплюються за допомогою операторів try/catch/finally, які описуються пізніше.

Оператор throw має наступний синтаксис:

throw вираз;

Результатом виразу може бути значення будь-якого типу. Оператору throw можна передати число, що представляє код помилки, або рядок, що містить текст повідомлення про помилку. Інтерпретатор JavaScript збуджує винятки, використовуючи екземпляр класу Error одного з його підкласів, і ви можете використовувати подібний підхід. Об'єкт Error має властивість name, що визначає тип помилки, та властивість message, Що містить рядок, передану функції-конструктору Нижче наведено приклад функції, яка збуджує об'єкт Error при виклику з неприпустимим аргументом:

// Функція факторіалу числа function factorial(number) ( // Якщо вхідний аргумент не є допустимим значенням, // збуджується виняток! if (number 1; i *= number, number--); /* порожнє тіло циклу */ return i ; ) console.log("5! = ", factorial(5)); console.log("-3! = ", factorial(-3));

Коли збуджується виняток, інтерпретатор JavaScript негайно перериває нормальне виконання програми та переходить до найближчого обробника винятків. У обробниках винятків використовується оператор catch конструкції try/catch/finally, опис якої наведено у наступному розділі.

Якщо блок програмного коду, в якому виник виняток, не має відповідної конструкції catch, інтерпретатор аналізує зовнішній блок програмного коду і перевіряє, чи пов'язаний з ним обробник винятків. Це триває доти, доки обробник не буде знайдено.

Якщо виняток генерується функції, що не містить конструкції try/catch/finally, призначеної для його обробки, то виняток поширюється вище, програмний код, що викликав функцію. Таким чином винятки поширюються за лексичною структурою методів JavaScriptвгору по стеку дзвінків. Якщо обробник виключення так і не буде знайдений, виняток розглядається як помилка і повідомляється користувачеві.

Конструкція try/catch/finally

Конструкція try/catch/finally реалізує механізм обробки винятків JavaScript. Оператор try у цій конструкції просто визначає блок коду, в якому обробляються винятки. За блоком try слід оператор catch з блоком інструкцій, що викликаються, якщо де-небудь у блоці try виникає виняток. За оператором catch слід блок finally містить програмний код, що виконує заключні операції, який гарантовано виконується незалежно від того, що відбувається в блоці try.

І блок catch, і блок finally не є обов'язковими, однак після блоку try повинен бути присутнім хоча б один з них. Блоки try, catch та finally починаються та закінчуються фігурними дужками. Це обов'язкова частина синтаксису і вона не може бути опущена, навіть якщо між ними міститься тільки одна інструкція.

Наступний фрагмент ілюструє синтаксис та призначення конструкції try/catch/finally:

Try (// Зазвичай цей код без збоїв працює від початку до кінця. // Але в якийсь момент у ньому може бути згенеровано виняток // або безпосередньо за допомогою оператора throw, або побічно - // викликом методу, що генерує виняток.) catch (ex) ( // Інструкції в цьому блоці виконуються тоді і тільки тоді, коли в блоці try // виникає виняток. Ці інструкції можуть використовувати локальну змінну ex, // посилається на об'єкт Error або інше значення, вказане в операторі throw. // Цей блок може або деяким чином обробити виняток, або // проігнорувати його, роблячи щось інше, або знову згенерувати // виняток за допомогою оператора throw ) finally ( // Цей блок містить інструкції, які виконуються завжди, незалежно від того , // що сталося у блоці try. Вони виконуються, якщо блок try завершився: // 1) як звичайно, досягнувши кінця блоку // 2) через операторів break, continue або return // 3) з винятком, обробленим наведеним у блоці catch вище // 4) з неперехопленим винятком, яке продовжує своє // поширення більш високі рівні )

Зауважте, що за ключовим словом catch слід ідентифікатор у дужках. Цей ідентифікатор нагадує параметр функції. Коли буде перехоплено виняток, цей параметр буде присвоєно виняток (наприклад, об'єкт Error). На відміну від звичайної змінної ідентифікатор, асоційований з оператором catch, існує лише у тілі блоку catch.

Далі наводиться реалістичніший приклад конструкції try/catch. У ньому викликаються метод factorial(), визначений у попередньому прикладі, та методи prompt() та alert() клієнтського JavaScript для організації введення та виведення:

Try ( // Запитати у користувача var n = Number(prompt("Введіть додатне число", "")); // Обчислити факторіал числа, припускаючи, // що вхідні дані коректні var f = factorial(n); // Вивести результат alert(n + "! = " + f); ) catch (ex) ( // Якщо дані некоректні, управління буде передано сюди alert(ex); // Повідомити користувача про помилку)

Якщо користувач введе від'ємне число, з'явиться попереджувальне повідомлення:

Це приклад конструкції try/catch без оператора finally. Хоча finally використовується не так часто, як catch, проте іноді цей оператор виявляється корисним. Блок finally гарантовано виконується, якщо виконувалася хоча б якась частина блоку try незалежно від того, яким чином завершилося виконання програмного коду в блоці try. Ця можливість зазвичай використовується для виконання заключних операцій після виконання програмного коду протягом try.

У звичайній ситуації управління сягає кінця блоку try, а потім переходить до блоку finally, який виконує необхідні заключні операції. Якщо управління вийшло з блоку try як результат виконання операторів return, continue або break, перед передачею управління інше місце виконується блок finally.

Якщо у блоці try виникає виняток і є відповідний блок catch для його обробки, керування спочатку передається в блок catch, а потім у блок finally. Якщо відсутній локальний блок catch, то керування спочатку передається до блоку finally, а потім переходить на найближчий зовнішній блок catch, який може обробити виняток.

Якщо сам блок finally передає керування за допомогою операторів return, continue, break або throw або шляхом виклику методу, що генерує виняток, незакінчена команда на передачу керування скасовується та виконується нова. Наприклад, якщо блок finally згенерує виняток, цей виняток замінить будь-який раніше згенерований виняток.

Функції є одним з найбільш важливих будівельних блоків коду JavaScript.

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

Код, поміщений у функцію, буде виконано лише після явного виклику цієї функції.

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

1. Синтаксис:

//Оголошення функції function ім'яФункції(пер1, пер2)( Код функції) //Виклик функції ім'яФункції(пер1,пер2);

2. Синтаксис:

// Оголошення функції var ім'я функції = function (пер1, пер2) (Код функції) // Виклик функції ім'я функції (пер1, пер2);

Ім'яфункції визначає ім'я функції. Кожна функція на сторінці має мати унікальне ім'я. Ім'я функції має бути задано латинськими літерами і починатися з цифр.

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

Зверніть увагу: навіть якщо у функцію не передаються змінні, не забувайте вставляти круглі дужки "()" після імені функції.

Зверніть увагу: імена функцій JavaScript чутливі до регістру.

Приклад JavaScript функції

Функція messageWrite() у наведеному нижче прикладі буде виконана тільки після натискання на кнопку.

Зверніть увагу: у цьому прикладі використовується подія onclick. Події JavaScriptбудуть детально розглянуті далі у цьому підручнику.

// Функція виводить текст на сторінку function messageWrite() ( document.write("Цей текст був виведений на сторінку за допомогою JavaScript!"); )

Передача функцій змінних

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

Зверніть увагу: всі маніпуляції над змінними всередині функцій насправді виконуються не над самими змінними, а над їх копією, тому вміст самих змінних у результаті виконання функцій не змінюється.

/* Задамо функцію, яка додає до переданої змінної 10 і виводить результат на сторінку */ function plus(a)( a=a+10; document.write("Виведення функції: " + a+"
"); ) var a=25; document.write("Значення змінної до виклику функції: "+a+"
"); // Викликаємо функцію передавши їй як аргумент змінну a plus(a); document.write("Значення змінної після виклику функції: "+a+"
");

Швидкий перегляд

Щоб звернутися до глобальної змінної з функції, а не її копії, використовуйте window.ім'я_змінної .

Function plus(a)( window.a=a+10; ) var a=25; document.write("Значення змінної до виклику функції: "+a+"
"); plus(a); document.write("Значення змінної після виклику функції: "+a+"
");

Швидкий перегляд

Команда return

За допомогою команди return можна повертати з функцій значення.

//Функція sum повертає суму переданих до неї змінних function sum(v1,v2)( return v1+v2; ) document.write("5+6=" + sum(5,6) + "
"); document.write("10+4=" + sum(10,4) + "
");

Швидкий перегляд

Вбудовані функції

Крім визначених користувачем функцій JavaScript існують ще й вбудовані функції .

Наприклад, вбудована функція isFinite дозволяє перевірити, чи є передане значення допустимим числом.

Document.write(isFinite(40)+"
"); document.write(isFinite(-590)+"
"); document.write(isFinite(90.33)+"
"); document.write(isFinite(NaN)+"
"); document.write(isFinite("Це рядок")+"
");

Швидкий перегляд

Зверніть увагу: повний списоквбудованих функцій JavaScript Ви можете знайти в нашому.

Локальні та глобальні змінні

Змінні функцій, що створюються всередині, називаються локальними змінними. Ви можете звертатися до таких змінних лише всередині функцій, у яких вони були визначені.

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

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

Якщо Ви оголошуєте змінну без var всередині функції, вона теж стає глобальною.

Глобальні змінні знищуються лише після закриття сторінки.

//Оголосимо глобальні змінні var1 та var2 var var1="var1 існує"; var var2; function func1() ( //Привласним var2 значення всередині функції func1 var var2="var2 існує"; ) //З іншої функції виведемо вміст змінної var1 і var2 на сторінку function func2() ( //Виводимо вміст змінної var1 document.write( var1 + "
"); //Виводимо вміст змінної var2 document.write(var2); )

Швидкий перегляд

Зверніть увагу: при виведенні на екран змінна var2 матиме порожнє значення, оскільки func1 оперує з локальною "версією" змінної var2.

Використання анонімних функцій

Функції, які не містять імені під час оголошення називаються анонімними .

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

Function arrMap(arr,func)( var res=new Array; for (var i=0;i target) return null; else return find(start + 5, "(" + history + " + 5)") || find (start * 3, "(" + history + " * 3)"); ) return find (1, "1"); ) console.log(findSolution(24)); // → (((1 * 3) + 5) * 3)

Цей приклад не обов'язково знаходить найкоротше рішення – він задовольняється будь-яким. Не чекаю, що ви одразу зрозумієте, як програма працює. Але давайте розбиратися в цій чудовій вправі на рекурсивне мислення.

Внутрішня функція find займається рекурсією. Вона приймає два аргументи – поточне число та рядок, який містить запис того, як ми прийшли до цього номеру. І повертає або рядок, що показує нашу послідовність кроків, або null.

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

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

Find(1, "1") find(6, "(1 + 5)") find(11, "((1 + 5) + 5)") find(16, "(((1 + 5) + 5) ) + 5)") too big find(33, "(((1 + 5) + 5) * 3)") too big find(18, "((1 + 5) * 3)") too big find( 3, "(1 * 3)") find (8, "((1 * 3) + 5)") find (13, "(((1 * 3) + 5) + 5)") found!

Відступ показує глибину стека дзвінків. Вперше функція find викликає сама себе двічі, щоб перевірити рішення, що починаються з (1+5) та (1*3). Перший виклик шукає рішення, що починається з (1 + 5), і за допомогою рекурсії перевіряє всі рішення, що видають число, менше або дорівнює необхідному. Не знаходить і повертає null. Тоді оператор || та переходить до виклику функції, який досліджує варіант (1*3). Тут на нас чекає успіх, тому що в третьому рекурсивному викликі ми отримуємо 13. Цей виклик повертає рядок, і кожен із операторів || шляхом передає цей рядок вище, в результаті повертаючи рішення.

Вирощуємо функції Існує два більш-менш природних способувведення функцій у програму.

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

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

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

007 Корів 011 Куриць

Очевидно, що нам знадобиться функція із двома аргументами. Починаємо кодувати.
// вивестиІнвентаризаціюФерми function printFarmInventory(cows, chickens) ( var cowString = String(cows); while (cowString.length< 3) cowString = "0" + cowString; console.log(cowString + " Коров"); var chickenString = String(chickens); while (chickenString.length < 3) chickenString = "0" + chickenString; console.log(chickenString + " Куриц"); } printFarmInventory(7, 11);

Якщо ми додамо до рядка.length, ми отримаємо її довжину. Виходить, що цикли while додають нулі спереду до числа, доки не отримають рядок в 3 символи.

Готово! Але тільки ми зібралися відправити фермеру код (разом із неабияким чеком, зрозуміло), він дзвонить і каже нам, що у нього в господарстві з'явилися свині, і чи не могли б ми додати до програми виведення кількості свиней?

Звичайно можна. Але коли ми починаємо копіювати та вставляти код із цих чотирьох рядків, ми розуміємо, що треба зупинитися і подумати. Має бути спосіб кращим. Намагаємось покращити програму:

// висновокДодаванняНулеюІміткою function printZeroPaddedWithLabel(number, label) ( var numberString = String(number); while (numberString.length< 3) numberString = "0" + numberString; console.log(numberString + " " + label); } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { printZeroPaddedWithLabel(cows, "Коров"); printZeroPaddedWithLabel(chickens, "Куриц"); printZeroPaddedWithLabel(pigs, "Свиней"); } printFarmInventory(7, 11, 3);

Працює! Але назва printZeroPaddedWithLabel трохи дивна. Воно поєднує три речі – висновок, додавання нулів та мітку – в одну функцію. Замість того, щоб вставляти в функцію весь фрагмент, що повторюється, давайте виділимо одну концепцію:

// додатиНуль function zeroPad(number, width) ( var string = String(number); while (string.length< width) string = "0" + string; return string; } // вывестиИнвентаризациюФермы function printFarmInventory(cows, chickens, pigs) { console.log(zeroPad(cows, 3) + " Коров"); console.log(zeroPad(chickens, 3) + " Куриц"); console.log(zeroPad(pigs, 3) + " Свиней"); } printFarmInventory(7, 16, 3);

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

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

Хороше правило - додавайте тільки ту функціональність, яка вам знадобиться. Іноді з'являється спокуса створювати фреймворки загального призначення кожної невеликої потреби. Опирайтеся йому. Ви ніколи не закінчите роботу, а просто напишете купу коду, який ніхто не використовуватиме.

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

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

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

Однак, не треба соромитися писати не зовсім чисті функції, або починати священне чищення коду від таких функцій. Побічні ефекти часто є корисними. Немає способу написати чисту версію функції console.log, і ця функція дуже корисна. Деякі операції легко висловити, використовуючи побічні ефекти.

Підсумок Цей розділ показав вам, як писати власні функції. Коли ключове словоФункція використовується як вираз, повертає покажчик на виклик функції. Коли використовується як інструкція, ви можете оголошувати змінну, призначаючи їй виклик функції.

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

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

ВправиМинимум У попередньому розділі була згадана функція Math.min, що повертає найменший з аргументів. Тепер ми можемо написати цю функцію самі. Напишіть функцію min, яка приймає два аргументи, і повертає мінімальний із них.

Console.log(min(0, 10)); // → 0 console.log (min (0, -10)); // → -10

Рекурсія Ми бачили, що оператор % (залишок від розподілу) може використовуватися визначення того, чи парне число (% 2). А ось ще один спосіб визначення:

Нуль парний.
Одиниця непарна.
У будь-якого числа N парність така сама, як у N-2.

Напишіть рекурсивну функцію isEven відповідно до цих правил. Вона має приймати число та повертати булевське значення.

Потестуйте її на 50 та 75. Спробуйте задати їй -1. Чому вона поводиться таким чином? Чи можна її якось виправити?

Test it on 50 and 75. See how it behaves on -1. Why? Чи може ви думати про те, що це?

Console.log(isEven(50)); // → true console.log(isEven(75)); // → false console.log(isEven(-1)); // → ??

Вважаємо боби.

Символ номер N рядка можна отримати, додавши до неї.charAt(N) (“рядок”.charAt(5)) – так само з отриманням довжини рядка за допомогою.length. Значення, що повертається буде рядковим, що складається з одного символу (наприклад, "к"). У першого символу рядка позиція 0, що означає, що у останнього символу позиція буде string.length – 1. Іншими словами, рядок з двох символів має довжину 2, а позиції її символів будуть 0 і 1.

Напишіть функцію countBs, яка приймає рядок як аргумент, та повертає кількість символів “B”, що містяться у рядку.

Потім напишіть функцію countChar, яка працює приблизно як countBs, тільки приймає другий параметр - символ, який ми шукатимемо в рядку (замість просто рахувати кількість символів “B”). Для цього переробіть функцію countBs.



Розповісти друзям