diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md index 7cbd85ab7..c4bc026d3 100644 --- a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md +++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md @@ -1,5 +1,5 @@ -The answer is: **Pete**. +Відповідь: **Петро**. -A function gets outer variables as they are now, it uses the most recent values. +Функція отримує зовнішні змінні такими, якими вони є зараз, тобто вона використовує останні значення. -Old variable values are not saved anywhere. When a function wants a variable, it takes the current value from its own Lexical Environment or the outer one. +Старі значення змінних ніде не зберігаються. Коли функція потребує змінної, вона бере поточне значення зі свого власного або зовнішнього лексичного середовища. diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md index 819189773..7d55c1562 100644 --- a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md +++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md @@ -2,22 +2,22 @@ importance: 5 --- -# Does a function pickup latest changes? +# Чи побачить функція останні зміни? -The function sayHi uses an external variable name. When the function runs, which value is it going to use? +Функція `sayHi` використовує зовнішню змінну. Яке значення буде використано під час виконання функції? ```js -let name = "John"; +let name = "Іван"; function sayHi() { - alert("Hi, " + name); + alert("Привіт, " + name); } -name = "Pete"; +name = "Петро"; -sayHi(); // what will it show: "John" or "Pete"? +sayHi(); // що вона покаже "Іван" чи "Петро"? ``` -Such situations are common both in browser and server-side development. A function may be scheduled to execute later than it is created, for instance after a user action or a network request. +Такі ситуації поширені як у браузері, так і в серверній розробці. Функцію можна запланувати на виконання пізніше, ніж вона створена, наприклад, після дії користувача або запиту мережі. -So, the question is: does it pick up the latest changes? +Отже, виникає питання: чи побачить функція останні зміни? diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js index a26578ae1..a30412cb1 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js +++ b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/solution.js @@ -3,8 +3,8 @@ function makeArmy() { let shooters = []; for(let i = 0; i < 10; i++) { - let shooter = function() { // shooter function - alert( i ); // should show its number + let shooter = function() { // функція shooter + alert( i ); // має показати свій номер }; shooters.push(shooter); } diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js index 7c7aaa1e3..716a982a3 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js +++ b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/source.js @@ -3,8 +3,8 @@ function makeArmy() { let i = 0; while (i < 10) { - let shooter = function() { // shooter function - alert( i ); // should show its number + let shooter = function() { // функція shooter + alert( i ); // має показати свій номер }; shooters.push(shooter); i++; @@ -16,7 +16,7 @@ function makeArmy() { /* let army = makeArmy(); -army[0](); // the shooter number 0 shows 10 -army[5](); // and number 5 also outputs 10... -// ... all shooters show 10 instead of their 0, 1, 2, 3... +army[0](); // стрілець під номером 0 показує 10 +army[5](); // п’ятий стрілець показує 10... +// ... всі стрільці показують 10 замість своїх номерів 0, 1, 2, 3... */ diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js index b61e6e4db..27d89debb 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js +++ b/1-js/06-advanced-functions/03-closure/10-make-army/_js.view/test.js @@ -7,13 +7,13 @@ describe("army", function() { window.alert = sinon.stub(window, "alert"); }); - it("army[0] shows 0", function() { + it("army[0] показує 0", function() { army[0](); assert(alert.calledWith(0)); }); - it("army[5] shows 5", function() { + it("army[5] показує 5", function() { army[5](); assert(alert.calledWith(5)); }); diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md index 9d99aa717..542945f54 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md @@ -1,14 +1,14 @@ -Let's examine what exactly happens inside `makeArmy`, and the solution will become obvious. +Давайте розберемося, що саме відбувається всередині функції `makeArmy`, і рішення стане очевидним. -1. It creates an empty array `shooters`: +1. Функція створює порожній масив `shooters`: ```js let shooters = []; ``` -2. Fills it with functions via `shooters.push(function)` in the loop. +2. Наповнює його функціями у циклі через `shooters.push(function)`. - Every element is a function, so the resulting array looks like this: + Кожен елемент є функцією, тому отриманий масив виглядає так: ```js no-beautify shooters = [ @@ -25,40 +25,40 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco ]; ``` -3. The array is returned from the function. +3. Функція повертає масив. - Then, later, the call to any member, e.g. `army[5]()` will get the element `army[5]` from the array (which is a function) and calls it. + Потім, виклик будь-якого елемента масиву, наприклад `army[5]()` отримає елемент `army[5]` з масиву (який є функцією) і викликає її. - Now why do all such functions show the same value, `10`? + Чому всі функції показують однакове значення, `10`? - That's because there's no local variable `i` inside `shooter` functions. When such a function is called, it takes `i` from its outer lexical environment. + Зверніть увагу, що всередині функцій `shooter` немає локальної змінної `i`. Коли така функція викликається, вона приймає `i` зі свого зовнішнього лексичного середовища. - Then, what will be the value of `i`? + Тоді яке буде значення `i`? - If we look at the source: + Якщо ми подивимося на код: ```js function makeArmy() { ... let i = 0; while (i < 10) { - let shooter = function() { // shooter function - alert( i ); // should show its number + let shooter = function() { // функція shooter + alert( i ); // має показати свій номер }; - shooters.push(shooter); // add function to the array + shooters.push(shooter); // додати функцію до масиву i++; } ... } ``` - We can see that all `shooter` functions are created in the lexical environment of `makeArmy()` function. But when `army[5]()` is called, `makeArmy` has already finished its job, and the final value of `i` is `10` (`while` stops at `i=10`). + Ми бачимо що усі функції `shooter` створені в лексичному середовищі функції `makeArmy()`. Але коли ми викликаємо `army[5]()`, функція `makeArmy` вже закінчила свою роботу, і остаточне значення `i` це `10` (цикл `while` зупиняється на `i=10`). - As the result, all `shooter` functions get the same value from the outer lexical environment and that is, the last value, `i=10`. + В результаті всі функції `shooter` отримують однакове значення із зовнішнього лексичного середовища, тобто останнє значення, `i=10`. ![](lexenv-makearmy-empty.svg) - As you can see above, on each iteration of a `while {...}` block, a new lexical environment is created. So, to fix this, we can copy the value of `i` into a variable within the `while {...}` block, like this: + Як ви можете бачити вище, на кожній ітерації циклу `while {...}`, створюється нове лексичне середовище. Отже, щоб виправити це, ми можемо скопіювати значення `i` у змінну всередині блоку `while {...}`, ось так: ```js run function makeArmy() { @@ -69,8 +69,8 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco *!* let j = i; */!* - let shooter = function() { // shooter function - alert( *!*j*/!* ); // should show its number + let shooter = function() { // функція shooter + alert( *!*j*/!* ); // має показати свій номер }; shooters.push(shooter); i++; @@ -81,18 +81,18 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco let army = makeArmy(); - // Now the code works correctly + // Тепер код працює правильно army[0](); // 0 army[5](); // 5 ``` - Here `let j = i` declares an "iteration-local" variable `j` and copies `i` into it. Primitives are copied "by value", so we actually get an independent copy of `i`, belonging to the current loop iteration. + Тут `let j = i` оголошує локальну змінну `j` та копіює до неї номер ітерації зі змінної `i`. Примітиви копіюються "за значенням", тому ми фактично отримуємо незалежну копію `i`, що належить до поточної ітерації циклу. - The shooters work correctly, because the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds to the current loop iteration: + Функції тепер працюють правильно, тому що змінна `i` "живе" трохи ближче. Не в лексичному середовищі виклику `makeArmy()`, але в лексичному середовищі, яке відповідає поточній ітерації циклу: ![](lexenv-makearmy-while-fixed.svg) - Such a problem could also be avoided if we used `for` in the beginning, like this: + Такої проблеми також можна було б уникнути, якби ми використали цикл `for` з самого початку, ось так: ```js run demo function makeArmy() { @@ -102,8 +102,8 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco *!* for(let i = 0; i < 10; i++) { */!* - let shooter = function() { // shooter function - alert( i ); // should show its number + let shooter = function() { // функція shooter + alert( i ); // має показати свій номер }; shooters.push(shooter); } @@ -117,13 +117,13 @@ Let's examine what exactly happens inside `makeArmy`, and the solution will beco army[5](); // 5 ``` - That's essentially the same, because `for` on each iteration generates a new lexical environment, with its own variable `i`. So `shooter` generated in every iteration references its own `i`, from that very iteration. + Це, по суті, те саме, тому що `for` на кожній ітерації створює нове лексичне середовище зі своєю змінною `i`. Тому `shooter` згенерований на кожній ітерації бере посилання на змінну `i`, з тієї самої ітерації. ![](lexenv-makearmy-for-fixed.svg) -Now, as you've put so much effort into reading this, and the final recipe is so simple - just use `for`, you may wonder -- was it worth that? +Тепер, коли ви доклали так багато зусиль, щоб прочитати це, остаточний рецепт такий простий -- використовуйте цикл `for`, ви можете задатися питанням -- чи було воно того варте? -Well, if you could easily answer the question, you wouldn't read the solution. So, hopefully this task must have helped you to understand things a bit better. +Ну, якби ви могли легко відповісти на запитання, ви б не читали рішення. Тож, сподіваюся, це завдання допомогло вам трохи краще зрозуміти як все працює. -Besides, there are indeed cases when one prefers `while` to `for`, and other scenarios, where such problems are real. +Крім того, на практиці бувають випадки, коли віддають перевагу `while` замість `for`, та інші сценарії, де такі проблеми є реальними. diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/task.md b/1-js/06-advanced-functions/03-closure/10-make-army/task.md index f50c7dc20..e5cd00973 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/task.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Army of functions +# Армія функцій -The following code creates an array of `shooters`. +Наступний код створює масив `shooters`. -Every function is meant to output its number. But something is wrong... +Кожна функція має вивести свій номер. Але щось не так... ```js run function makeArmy() { @@ -14,28 +14,28 @@ function makeArmy() { let i = 0; while (i < 10) { - let shooter = function() { // create a shooter function, - alert( i ); // that should show its number + let shooter = function() { // створюємо функцію стрільця, + alert( i ); // що має показувати свій номер }; - shooters.push(shooter); // and add it to the array + shooters.push(shooter); // додаємо її до масиву i++; } - // ...and return the array of shooters + // ...і повертаємо масив стрільців return shooters; } let army = makeArmy(); *!* -// all shooters show 10 instead of their numbers 0, 1, 2, 3... -army[0](); // 10 from the shooter number 0 -army[1](); // 10 from the shooter number 1 -army[2](); // 10 ...and so on. +// всі стрільці показують 10 замість своїх номерів 0, 1, 2, 3... +army[0](); // 10 від стрільця за номером 0 +army[1](); // 10 від стрільця за номером 1 +army[2](); // 10 ...і так далі. */!* ``` -Why do all of the shooters show the same value? +Чому всі функції показують однакове значення? -Fix the code so that they work as intended. +Виправте код так, щоб він працював як передбачалося. diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md index 0a522132f..03b1d50c7 100644 --- a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md +++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md @@ -1,9 +1,9 @@ -The answer is: **Pete**. +Відповідь: **Петро**. -The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference: +Функція `work()` в коді нижче отримує `name` від місця його походження через посилання на зовнішнє лексичне середовище: ![](lexenv-nested-work.svg) -So, the result is `"Pete"` here. +Отже, відповіддю буде `"Петро"`. -But if there were no `let name` in `makeWorker()`, then the search would go outside and take the global variable as we can see from the chain above. In that case the result would be `"John"`. +Але якби не було `let name` у `makeWorker()`, тоді пошук вийшов би за межі лексичного середовища та взяв би глобальну змінну, як ми бачимо з ланцюжка вище. В такому випадку відповідь була б `"Іван"`. diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md index d12a385c8..f382d0015 100644 --- a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md +++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md @@ -2,28 +2,28 @@ importance: 5 --- -# Which variables are available? +# Які змінні доступні? -The function `makeWorker` below makes another function and returns it. That new function can be called from somewhere else. +Функція `makeWorker` створює іншу функцію і повертає її. Цю нову функцію можна викликати ще звідкись. -Will it have access to the outer variables from its creation place, or the invocation place, or both? +Чи матиме вона доступ до зовнішніх змінних з місця створення, з місця виклику, чи з обох? ```js function makeWorker() { - let name = "Pete"; + let name = "Петро"; return function() { alert(name); }; } -let name = "John"; +let name = "Іван"; -// create a function +// створити функцію let work = makeWorker(); -// call it -work(); // what will it show? +// викликати її +work(); // Що вона покаже? ``` -Which value it will show? "Pete" or "John"? +Яке значення вона покаже? "Петро" чи "Іван"? diff --git a/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md index 25ecbea4c..2ce91538f 100644 --- a/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md +++ b/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md @@ -1,5 +1,5 @@ -The answer: **0,1.** +Відповідь: **0,1.** -Functions `counter` and `counter2` are created by different invocations of `makeCounter`. +Функції `counter` і `counter2` створюються різними викликами `makeCounter`. -So they have independent outer Lexical Environments, each one has its own `count`. +Отже, вони мають незалежні зовнішні лексичні середовища, кожне з яких має свою власну змінну `count`. diff --git a/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md index e8c17dd31..5c55263a8 100644 --- a/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md +++ b/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Are counters independent? +# Чи лічильники незалежні? -Here we make two counters: `counter` and `counter2` using the same `makeCounter` function. +Тут ми створюємо два лічильника: `counter` та `counter2` використовуючи однакову функцію `makeCounter`. -Are they independent? What is the second counter going to show? `0,1` or `2,3` or something else? +Вони незалежні? Що покаже другий лічильник? `0,1` чи `2,3` чи щось інше? ```js function makeCounter() { diff --git a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md index cd4e641e4..0d1a30a9d 100644 --- a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md +++ b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/solution.md @@ -1,7 +1,7 @@ -Surely it will work just fine. +Безумовно, він буде чудово працювати. -Both nested functions are created within the same outer Lexical Environment, so they share access to the same `count` variable: +Обидві вкладені функції створюються в межах єдиного зовнішнього лексичного середовища, тому вони мають спільний доступ до однієї змінної `count`: ```js run function Counter() { diff --git a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md index d770b0ffc..1a14db5c7 100644 --- a/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md +++ b/1-js/06-advanced-functions/03-closure/4-counter-object-independent/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Counter object +# Об’єкт лічильника -Here a counter object is made with the help of the constructor function. +Тут лічильник створюється за допомогою функції конструктора. -Will it work? What will it show? +Чи буде він працювати? Що він покаже? ```js function Counter() { diff --git a/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md index e2e7a91b3..6317f2e5e 100644 --- a/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md +++ b/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md @@ -1,3 +1,3 @@ -The result is **an error**. +Результатом буде **помилка**. -The function `sayHi` is declared inside the `if`, so it only lives inside it. There is no `sayHi` outside. \ No newline at end of file +Функція `sayHi` оголошується всередині `if`, тому вона доступна тільки всередині нього. Зовні функції `sayHi` не існує. \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md index d02c53b99..f02a75814 100644 --- a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md +++ b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md @@ -1,13 +1,13 @@ -# Function in if +# Функція у if -Look at the code. What will be the result of the call at the last line? +Подивіться на код. Яким буде результат виклику на останньому рядку? ```js run -let phrase = "Hello"; +let phrase = "Привіт"; if (true) { - let user = "John"; + let user = "Іван"; function sayHi() { alert(`${phrase}, ${user}`); diff --git a/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md index a6679cd20..09bc49ce5 100644 --- a/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md +++ b/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md @@ -1,12 +1,12 @@ -For the second parentheses to work, the first ones must return a function. +Щоб другі дужки працювали, функція повинна повертати іншу функцію. -Like this: +Ось так: ```js run function sum(a) { return function(b) { - return a + b; // takes "a" from the outer lexical environment + return a + b; // Бере "a" із зовнішнього лексичного середовища }; } diff --git a/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md index b45758562..a245f7fff 100644 --- a/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md +++ b/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md @@ -2,13 +2,13 @@ importance: 4 --- -# Sum with closures +# Сума із замиканням -Write function `sum` that works like this: `sum(a)(b) = a+b`. +Напишіть функцію `sum` яка працює ось так: `sum(a)(b) = a+b`. -Yes, exactly this way, using double parentheses (not a mistype). +Саме так, використовуючи подвійні дужки (це не друкарська помилка). -For instance: +Наприклад: ```js sum(1)(2) = 3 diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md index b16b35290..cccecb36e 100644 --- a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md +++ b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md @@ -1,6 +1,6 @@ -The result is: **error**. +Результатом буде **помилка**. -Try running it: +Спробуйте запустити це: ```js run let x = 1; @@ -15,20 +15,20 @@ function func() { func(); ``` -In this example we can observe the peculiar difference between a "non-existing" and "uninitialized" variable. +У цьому прикладі ми можемо спостерігати особливу різницю між "неіснуючою" та "неініціалізованою" змінною. -As you may have read in the article [](info:closure), a variable starts in the "uninitialized" state from the moment when the execution enters a code block (or a function). And it stays uninitalized until the corresponding `let` statement. +Як ви могли прочитати в статті [](info:closure), змінна перебуває у "неініціалізованому" стані з моменту, коли виконання входить в кодовий блок (чи у функцію). І вона залишається неініціалізованою до відповідного `let`. -In other words, a variable technically exists, but can't be used before `let`. +Інакше кажучи, змінна технічно існує, але не може бути використана раніше `let`. -The code above demonstrates it. +Наведений нижче код це демонструє. ```js function func() { *!* - // the local variable x is known to the engine from the beginning of the function, - // but "uninitialized" (unusable) until let ("dead zone") - // hence the error + // локальна змінна `x` відома рушію з початку функції, + // але вона "неініціалізова" (непридатна) до let ("мертва зона") + // звідси помилка */!* console.log(x); // ReferenceError: Cannot access 'x' before initialization @@ -37,4 +37,4 @@ function func() { } ``` -This zone of temporary unusability of a variable (from the beginning of the code block till `let`) is sometimes called the "dead zone". +Цю зону тимчасової непридатності змінної (від початку блоку коду до `let`) іноді називають "мертвою зоною". diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/task.md b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md index fb7445e66..d088a2371 100644 --- a/1-js/06-advanced-functions/03-closure/7-let-scope/task.md +++ b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md @@ -2,9 +2,9 @@ importance: 4 --- -# Is variable visible? +# Чи видно змінну? -What will be the result of this code? +Який буде результат цього коду? ```js let x = 1; @@ -18,4 +18,4 @@ function func() { func(); ``` -P.S. There's a pitfall in this task. The solution is not obvious. +P.S. У цьому завданні є підводний камінь. Рішення не є очевидним. diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js index 74989df28..6285cb288 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/source.js @@ -2,9 +2,9 @@ let arr = [1, 2, 3, 4, 5, 6, 7]; function inBetween(a, b) { - // ...your code... + // ...ваш код... } function inArray(arr) { - // ...your code... + // ...ваш код... } diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js index 86d2d3b48..30893cf87 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/_js.view/test.js @@ -2,7 +2,7 @@ describe("inArray", function() { let arr = [1, 2, 3, 4, 5, 6, 7]; - it("returns the filter for values in array", function() { + it("повертає значення, які включено до масиву", function() { let filter = inArray(arr); assert.isTrue(filter(5)); @@ -13,7 +13,7 @@ describe("inArray", function() { describe("inBetween", function() { - it("returns the filter for values between", function() { + it("повертає масив зі значеннями між заданими", function() { let filter = inBetween(3, 6); assert.isTrue(filter(5)); assert.isFalse(filter(0)); diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md index 46c5514a8..b8b736907 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md @@ -1,5 +1,5 @@ -# Filter inBetween +# Фільтр inBetween ```js run function inBetween(a, b) { @@ -12,7 +12,7 @@ let arr = [1, 2, 3, 4, 5, 6, 7]; alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6 ``` -# Filter inArray +# Фільтр inArray ```js run demo function inArray(arr) { diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md index d1c39f949..84d489988 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md @@ -2,24 +2,24 @@ importance: 5 --- -# Filter through function +# Функції фільтрації -We have a built-in method `arr.filter(f)` for arrays. It filters all elements through the function `f`. If it returns `true`, then that element is returned in the resulting array. +У нас є вбудований для масивів метод `arr.filter(f)`. Він фільтрує всі елементи через функцію `f`. Якщо вона повертає `true`, цей елемент повертається в отриманому масиві. -Make a set of "ready to use" filters: +Зробіть набір "готових до використання" фільтрів: -- `inBetween(a, b)` -- between `a` and `b` or equal to them (inclusively). -- `inArray([...])` -- in the given array. +- `inBetween(a, b)` -- фільтрує елементи які більше `a` та менше `b`. Також має включати елементи, які дорівнюють їм. +- `inArray([...])` -- фільтрує елементи, які включено у заданий масив. -The usage must be like this: +Використання має бути таким: -- `arr.filter(inBetween(3,6))` -- selects only values between 3 and 6. -- `arr.filter(inArray([1,2,3]))` -- selects only elements matching with one of the members of `[1,2,3]`. +- `arr.filter(inBetween(3,6))` -- вибирає лише значення від 3 до 6. +- `arr.filter(inArray([1,2,3]))` -- вибирає лише елементи, які включені у масив `[1,2,3]`. -For instance: +Наприклад: ```js -/* .. your code for inBetween and inArray */ +/* .. ваш код для inBetween та inArray */ let arr = [1, 2, 3, 4, 5, 6, 7]; alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6 diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js index 23b433834..f22cd536c 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/source.js @@ -1,5 +1,4 @@ function byField(fieldName){ - // Your code goes here. - + // Ваш код } diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js index 802f28c4d..b34791b58 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js @@ -1,36 +1,36 @@ describe("byField", function(){ let users = [ - { name: "John", age: 20, surname: "Johnson" }, - { name: "Pete", age: 18, surname: "Peterson" }, - { name: "Ann", age: 19, surname: "Hathaway" }, + { name: "Іван", age: 20, surname: "Іванов" }, + { name: "Петро", age: 18, surname: "Петров" }, + { name: "Енн", age: 19, surname: "Гетевей" }, ]; - it("sorts users by name", function(){ + it("сортує користувачів за іменами", function(){ let nameSortedKey = [ - { name: "Ann", age: 19, surname: "Hathaway" }, - { name: "John", age: 20, surname: "Johnson"}, - { name: "Pete", age: 18, surname: "Peterson" }, + { name: "Енн", age: 19, surname: "Гетевей" }, + { name: "Іван", age: 20, surname: "Іванов"}, + { name: "Петро", age: 18, surname: "Петров" }, ]; let nameSortedAnswer = users.sort(byField("name")); assert.deepEqual(nameSortedKey, nameSortedAnswer); }); - it("sorts users by age", function(){ + it("сортує користувачів за віком", function(){ let ageSortedKey = [ - { name: "Pete", age: 18, surname: "Peterson" }, - { name: "Ann", age: 19, surname: "Hathaway" }, - { name: "John", age: 20, surname: "Johnson"}, + { name: "Петро", age: 18, surname: "Петров" }, + { name: "Енн", age: 19, surname: "Гетевей" }, + { name: "Іван", age: 20, surname: "Іванов"}, ]; let ageSortedAnswer = users.sort(byField("age")); assert.deepEqual(ageSortedKey, ageSortedAnswer); }); - it("sorts users by surname", function(){ + it("сортує користувачів за прізвищем", function(){ let surnameSortedKey = [ - { name: "Ann", age: 19, surname: "Hathaway" }, - { name: "John", age: 20, surname: "Johnson"}, - { name: "Pete", age: 18, surname: "Peterson" }, + { name: "Енн", age: 19, surname: "Гетевей" }, + { name: "Іван", age: 20, surname: "Іванов"}, + { name: "Петро", age: 18, surname: "Петров" }, ]; let surnameSortedAnswer = users.sort(byField("surname")); assert.deepEqual(surnameSortedAnswer, surnameSortedKey); diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md b/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md index 08fb5cc34..eb9e533b2 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/task.md @@ -2,35 +2,35 @@ importance: 5 --- -# Sort by field +# Сортувати за полем -We've got an array of objects to sort: +У нас є масив об’єктів для сортування: ```js let users = [ - { name: "John", age: 20, surname: "Johnson" }, - { name: "Pete", age: 18, surname: "Peterson" }, - { name: "Ann", age: 19, surname: "Hathaway" } + { name: "Іван", age: 20, surname: "Іванов" }, + { name: "Петро", age: 18, surname: "Петров" }, + { name: "Енн", age: 19, surname: "Гетевей" } ]; ``` -The usual way to do that would be: +Звичайний спосіб зробити це: ```js -// by name (Ann, John, Pete) +// За ім’ям (Енн, Іван, Петро) users.sort((a, b) => a.name > b.name ? 1 : -1); -// by age (Pete, Ann, John) +// За віком (Петро, Енн, Іван) users.sort((a, b) => a.age > b.age ? 1 : -1); ``` -Can we make it even less verbose, like this? +Чи можемо ми зробити це ще менш багатослівним? ```js users.sort(byField('name')); users.sort(byField('age')); ``` -So, instead of writing a function, just put `byField(fieldName)`. +Отже, замість того, щоб кожен раз писати функцію, ми будемо викликати функцію `byField(fieldName)`. -Write the function `byField` that can be used for that. +Напишіть функцію `byField` яка може бути використана для цього. diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index 199887063..9db5e5cee 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -1,130 +1,130 @@ -# Variable scope, closure +# Область видимості змінної, замикання -JavaScript is a very function-oriented language. It gives us a lot of freedom. A function can be created at any moment, passed as an argument to another function, and then called from a totally different place of code later. +JavaScript -- це дуже функціонально орієнтована мова. Це дає нам багато свободи. Функцію можна створити в будь-який момент, її можна передати як аргумент іншій функції, а потім викликати з абсолютно іншого місця коду. -We already know that a function can access variables outside of it ("outer" variables). +Ми вже знаємо, що функція може отримати доступ до змінних з зовнішнього середовища (зовнішні змінні). -But what happens if outer variables change since a function is created? Will the function get newer values or the old ones? +Але що станеться, якщо зовнішні змінні змінюються після створення функції? Чи отримає функція нові значення чи старі? -And what if a function is passed along as a parameter and called from another place of code, will it get access to outer variables at the new place? +А що буде, коли функція передається як параметр і викликається з іншого місця коду, чи отримає вона доступ до зовнішніх змінних на новому місці? -Let's expand our knowledge to understand these scenarios and more complex ones. +Давайте розширимо наші знання, щоб зрозуміти ці та більш складні сценарії. -```smart header="We'll talk about `let/const` variables here" -In JavaScript, there are 3 ways to declare a variable: `let`, `const` (the modern ones), and `var` (the remnant of the past). +```smart header="Тут ми поговоримо про змінні `let/const`" +У JavaScript існує 3 способи оголошення змінної: `let`, `const` (сучасні способи) та `var` (залишок минулого). -- In this article we'll use `let` variables in examples. -- Variables, declared with `const`, behave the same, so this article is about `const` too. -- The old `var` has some notable differences, they will be covered in the article . +- У цій статті ми будемо використовувати `let` для змінних у прикладах. +- Змінні, оголошені через `const`, поводяться так само, тому ця стаття також стосується `const`. +- `var` має деякі помітні відмінності, вони будуть розглянуті в статті . ``` -## Code blocks +## Блоки коду -If a variable is declared inside a code block `{...}`, it's only visible inside that block. +Якщо змінна оголошена всередині блоку коду `{...}`, вона буде доступна лише всередині цього блоку. -For example: +Наприклад: ```js run { - // do some job with local variables that should not be seen outside + // тут виконується певна робота з локальними змінними, яку не слід бачити зовні - let message = "Hello"; // only visible in this block + let message = "Привіт"; // змінна видима тільки у цьому блоці - alert(message); // Hello + alert(message); // Привіт } -alert(message); // Error: message is not defined +alert(message); // Помилка: змінну message не було оголошено ``` -We can use this to isolate a piece of code that does its own task, with variables that only belong to it: +Ми можемо використовувати це, щоб виділити фрагмент коду, який працює зі змінними, які доступні лише з нього: ```js run { - // show message - let message = "Hello"; + // показати повідомлення + let message = "Привіт"; alert(message); } { - // show another message - let message = "Goodbye"; + // показати інше повідомлення + let message = "Бувай"; alert(message); } ``` -````smart header="There'd be an error without blocks" -Please note, without separate blocks there would be an error, if we use `let` with the existing variable name: +````smart header="Без блоків буде помилка" +Будь-ласка, зверніть увагу, що без окремих блоків буде помилка, якщо ми використовуємо `let` з однаковою назвою змінної: ```js run -// show message -let message = "Hello"; +// показати повідомлення +let message = "Привіт"; alert(message); -// show another message +// показати інше повідомлення *!* -let message = "Goodbye"; // Error: variable already declared +let message = "Бувай"; // Помилка: змінна вже оголошена */!* alert(message); ``` ```` -For `if`, `for`, `while` and so on, variables declared in `{...}` are also only visible inside: +Для `if`, `for`, `while` і так далі, змінні, оголошені в `{...}` також видно тільки всередині: ```js run if (true) { - let phrase = "Hello!"; + let phrase = "Привіт!"; - alert(phrase); // Hello! + alert(phrase); // Привіт! } -alert(phrase); // Error, no such variable! +alert(phrase); // Помилка, такої змінної немає! ``` -Here, after `if` finishes, the `alert` below won't see the `phrase`, hence the error. +Тут, після завершення `if`, `alert` нижче не побачить `phrase`, отже, помилка. -That's great, as it allows us to create block-local variables, specific to an `if` branch. +Це чудово, оскільки це дозволяє нам створювати локально-блокові змінні, специфічні для гілки `if`. -The similar thing holds true for `for` and `while` loops: +Те ж саме справедливо і для циклів `for` та `while`: ```js run for (let i = 0; i < 3; i++) { - // the variable i is only visible inside this for - alert(i); // 0, then 1, then 2 + // змінну `i` видно тільки всередині цього циклу for + alert(i); // 0, потім 1, потім 2 } -alert(i); // Error, no such variable +alert(i); // Помилка, такої змінної немає ``` -Visually, `let i` is outside of `{...}`. But the `for` construct is special here: the variable, declared inside it, is considered a part of the block. +Візуально, `let i` знаходиться за межами `{...}`. Але конструкція `for` особлива: змінна, оголошена всередині неї, вважається частиною блоку. -## Nested functions +## Вкладені функції -A function is called "nested" when it is created inside another function. +Функція називається "вкладеною", коли вона створюється всередині іншої функції. -It is easily possible to do this with JavaScript. +З JavaScript це зробити дуже легко. -We can use it to organize our code, like this: +І ми можемо використовувати це для організації нашого коду, наприклад: ```js function sayHiBye(firstName, lastName) { - // helper nested function to use below + // допоміжна вкладена функція для використання нижче function getFullName() { return firstName + " " + lastName; } - alert( "Hello, " + getFullName() ); - alert( "Bye, " + getFullName() ); + alert( "Привіт, " + getFullName() ); + alert( "Бувай, " + getFullName() ); } ``` -Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name. Nested functions are quite common in JavaScript. +Тут *вкладена* функція `getFullName()` створена для зручності. Вона має доступ до внутрішніх змінних функції і тому може повернути повне ім’я. Вкладені функції досить поширені в JavaScript. -What's much more interesting, a nested function can be returned: either as a property of a new object or as a result by itself. It can then be used somewhere else. No matter where, it still has access to the same outer variables. +Що ще цікавіше, вкладену функцію можна повернути: як властивість нового об’єкта, або як самостійний результат. Потім її можна використати десь в іншому місці. Незалежно від того, де її викликають, вона завжди буде мати доступ до внутрішніх змінних функцію, в якій її було створено. -Below, `makeCounter` creates the "counter" function that returns the next number on each invocation: +Нижче, `makeCounter` створює функцію "counter", яка повертає наступний номер при кожному виклику: ```js run function makeCounter() { @@ -142,87 +142,87 @@ alert( counter() ); // 1 alert( counter() ); // 2 ``` -Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) to generate random values for automated tests. +Незважаючи на простоту, трохи змінені варіанти цього коду мають практичне застосування, наприклад, [генератор псевдовипадкових чисел](https://uk.wikipedia.org/wiki/Генератор_псевдовипадкових_чисел) для генерації випадкових значень для автоматизованих тестів. -How does this work? If we create multiple counters, will they be independent? What's going on with the variables here? +Як це працює? Якщо ми створимо кілька лічильників, чи будуть вони незалежними? Що відбувається зі змінними тут? -Understanding such things is great for the overall knowledge of JavaScript and beneficial for more complex scenarios. So let's go a bit in-depth. +Розуміння таких речей чудово не тільки для загального знання JavaScript, але й корисно для роботи з більш складними сценаріями. Тож давайте трохи поглибимося. -## Lexical Environment +## Лексичне середовище -```warn header="Here be dragons!" -The in-depth technical explanation lies ahead. +```warn header="Тут будуть дракони!" +Поглиблене технічне пояснення попереду. -As far as I'd like to avoid low-level language details, any understanding without them would be lacking and incomplete, so get ready. +Чесно кажучи, пояснюючи це, я хотів би уникнути низькорівневих деталей, але без них розуміння буде не повним, тому готуйтесь. ``` -For clarity, the explanation is split into multiple steps. +Для наочності пояснення поділено на кілька етапів. -### Step 1. Variables +### 1 етап. Змінні -In JavaScript, every running function, code block `{...}`, and the script as a whole have an internal (hidden) associated object known as the *Lexical Environment*. +У JavaScript кожна запущена функція, блок коду `{...}`, і скрипт в цілому мають внутрішній (прихований) асоційований об’єкт, відомий як *Лексичне середовище (Lexical Environment)*. -The Lexical Environment object consists of two parts: +Об’єкт лексичного середовища складається з двох частин: -1. *Environment Record* -- an object that stores all local variables as its properties (and some other information like the value of `this`). -2. A reference to the *outer lexical environment*, the one associated with the outer code. +1. *Запис середовища (Environment Record)* -- об’єкт, який зберігає всі локальні змінні як властивості (та деяку іншу інформацію, наприклад значення `this`). +2. Посилання на *зовнішнє лексичне середовище*, яке пов’язане із зовнішнім кодом. -**A "variable" is just a property of the special internal object, `Environment Record`. "To get or change a variable" means "to get or change a property of that object".** +**"Змінна" це лише властивість спеціального внутрішнього об’єкта, `Запис середовища (Environment Record)`. "Отримати або змінити змінну" насправді означає "отримати або змінити властивість цього об’єкта".** -In this simple code without functions, there is only one Lexical Environment: +У цьому простому коді без функцій є лише одне лексичне середовище: ![lexical environment](lexical-environment-global.svg) -This is the so-called *global* Lexical Environment, associated with the whole script. +Це так зване *глобальне* лексичне середовище, пов’язане з усім скриптом. -On the picture above, the rectangle means Environment Record (variable store) and the arrow means the outer reference. The global Lexical Environment has no outer reference, that's why the arrow points to `null`. +На зображенні вище прямокутник означає запис середовища (сховище змінних), а стрілка означає зовнішнє посилання. Глобальне лексичне середовище не має зовнішнього посилання, тому стрілка вказує на `null`. -As the code starts executing and goes on, the Lexical Environment changes. +Коли код виконується, лексичне середовище змінюється. -Here's a little bit longer code: +Ось трохи довший код: ![lexical environment](closure-variable-phrase.svg) -Rectangles on the right-hand side demonstrate how the global Lexical Environment changes during the execution: +Прямокутники праворуч демонструють, як змінюється глобальне лексичне середовище під час виконання: -1. When the script starts, the Lexical Environment is pre-populated with all declared variables. - - Initially, they are in the "Uninitialized" state. That's a special internal state, it means that the engine knows about the variable, but it cannot be referenced until it has been declared with `let`. It's almost the same as if the variable didn't exist. -2. Then `let phrase` definition appears. There's no assignment yet, so its value is `undefined`. We can use the variable from this point forward. -3. `phrase` is assigned a value. -4. `phrase` changes the value. +1. Коли скрипт запускається, лексичне середовище попередньо заповнюється усіма оголошеними змінними. + - Спочатку вони перебувають у стані "Неініціалізовано" (Uninitialized). Це особливий внутрішній стан, який означає, що рушій знає про змінну, але на неї не можна посилатися, поки вона не буде оголошена з `let`. Це майже те саме, ніби змінна не існує. +2. Потім з’являється оголошення змінної `let phrase`. Поки що ми тільки оголосили змінну, тому її значення `undefined`. Але з цього моменту ми можемо використовувати її. +3. `phrase` присвоюється значення. +4. `phrase` змінює значення. -Everything looks simple for now, right? +Поки що все виглядає просто, правда? -- A variable is a property of a special internal object, associated with the currently executing block/function/script. -- Working with variables is actually working with the properties of that object. +- Змінна -- це властивість спеціального внутрішнього об’єкта, пов’язана з блоком/функцієї/скриптом що зараз виконується. +- Робота зі змінними -- це насправді робота з властивостями цього об’єкта. -```smart header="Lexical Environment is a specification object" -"Lexical Environment" is a specification object: it only exists "theoretically" in the [language specification](https://tc39.es/ecma262/#sec-lexical-environments) to describe how things work. We can't get this object in our code and manipulate it directly. +```smart header="Лексичне середовище -- це об'єкт специфікації" +"Лексичне середовище" -- це об’єкт специфікації: він існує лише "теоретично" в [специфікації мови](https://tc39.es/ecma262/#sec-lexical-environments) щоб показати, як все працює. Ми не можемо отримати цей об’єкт у нашому коді та керувати ним безпосередньо. -JavaScript engines also may optimize it, discard variables that are unused to save memory and perform other internal tricks, as long as the visible behavior remains as described. +Рушії JavaScript також можуть його оптимізувати, відкидати змінні, які не використовуються для економії пам’яті та виконувати інші внутрішні трюки, доки видима поведінка залишається такою, як описано у специфікації. ``` -### Step 2. Function Declarations +### 2 етап. Функції створені як Function Declarations -A function is also a value, like a variable. +Функція також є значенням, як і значення у змінних. -**The difference is that a Function Declaration is instantly fully initialized.** +**Різниця в тому, що функція створена за допомогою Function Declaration, ініціалізується миттєво і повністю.** -When a Lexical Environment is created, a Function Declaration immediately becomes a ready-to-use function (unlike `let`, that is unusable till the declaration). +Коли створюється лексичне середовище, така функція відразу стає готовою до використання (на відміну від значення у змінній `let`, що непридатна для викорстиння до оголошення). -That's why we can use a function, declared as Function Declaration, even before the declaration itself. +Ось чому ми можемо використовувати функцію, оголошену з Function Declaration, ще до рядка з оголошенням. -For example, here's the initial state of the global Lexical Environment when we add a function: +Наприклад, ось початковий стан глобального лексичного середовища, коли ми додаємо функцію: ![](closure-function-declaration.svg) -Naturally, this behavior only applies to Function Declarations, not Function Expressions where we assign a function to a variable, such as `let say = function(name)...`. +Така поведінка стосується лише Function Declarations, а не Function Expressions, де ми призначаємо функцію змінній, наприклад ось так `let say = function(name)...`. -### Step 3. Inner and outer Lexical Environment +### 3 етап. Внутрішнє та зовнішнє лексичне середовище -When a function runs, at the beginning of the call, a new Lexical Environment is created automatically to store local variables and parameters of the call. +Коли функція виконується, на початку виклику автоматично створюється нове лексичне середовище для зберігання локальних змінних та параметрів виклику. -For instance, for `say("John")`, it looks like this (the execution is at the line, labelled with an arrow): +Наприклад, для `say("John")`, це виглядає так (виконання знаходиться у рядку, позначеному стрілкою):