From a11e2a33be4a36db46a472711f016e3c0d7e2e4b Mon Sep 17 00:00:00 2001 From: regnised Date: Sat, 14 Aug 2021 22:50:30 +0300 Subject: [PATCH 01/27] Objects --- .../01-object/2-hello-object/solution.md | 6 +- .../01-object/2-hello-object/task.md | 14 +- .../01-object/3-is-empty/_js.view/solution.js | 2 +- .../01-object/3-is-empty/_js.view/test.js | 6 +- .../01-object/3-is-empty/solution.md | 2 +- .../01-object/3-is-empty/task.md | 8 +- .../01-object/5-sum-object/task.md | 8 +- .../8-multiply-numeric/_js.view/source.js | 4 +- .../8-multiply-numeric/_js.view/test.js | 12 +- .../01-object/8-multiply-numeric/task.md | 18 +- 1-js/04-object-basics/01-object/article.md | 356 +++++++++--------- 11 files changed, 218 insertions(+), 218 deletions(-) diff --git a/1-js/04-object-basics/01-object/2-hello-object/solution.md b/1-js/04-object-basics/01-object/2-hello-object/solution.md index 60083b963..efbbcdc98 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/solution.md +++ b/1-js/04-object-basics/01-object/2-hello-object/solution.md @@ -2,9 +2,9 @@ ```js let user = {}; -user.name = "John"; -user.surname = "Smith"; -user.name = "Pete"; +user.name = "Іван"; +user.surname = "Сміт"; +user.name = "Петро"; delete user.name; ``` diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index 2841a058f..fe5f738e5 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Hello, object +# Привіт, object -Write the code, one line for each action: +Напишіть код, виконавши завдання з кожного пункту окремим рядком: -1. Create an empty object `user`. -2. Add the property `name` with the value `John`. -3. Add the property `surname` with the value `Smith`. -4. Change the value of the `name` to `Pete`. -5. Remove the property `name` from the object. +1. Створіть порожній об’єкт `user`. +2. Додайте властивість `ім’я` зі значенням `Іван`. +3. Додайте властивість `прізвище` зі значенням `Сміт`. +4. Змініть значення `ім’я` на `Петро`. +5. Видаліть властивість `ім’я` з об’єкта. diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js index db3283e49..c591643ad 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js @@ -1,6 +1,6 @@ function isEmpty(obj) { for (let key in obj) { - // if the loop has started, there is a property + // якщо цикл розпочався, властивість є return false; } return true; diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js index 4db5efabe..bb2206d54 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/test.js @@ -1,9 +1,9 @@ -describe("isEmpty", function() { - it("returns true for an empty object", function() { +describe("Порожньо?", function() { + it(`повертає "true" для порожнього об’єкта`, function() { assert.isTrue(isEmpty({})); }); - it("returns false if a property exists", function() { + it(`повертає "false" якщо властивість існує`, function() { assert.isFalse(isEmpty({ anything: false })); diff --git a/1-js/04-object-basics/01-object/3-is-empty/solution.md b/1-js/04-object-basics/01-object/3-is-empty/solution.md index b876973b5..739cf49c0 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/solution.md +++ b/1-js/04-object-basics/01-object/3-is-empty/solution.md @@ -1 +1 @@ -Just loop over the object and `return false` immediately if there's at least one property. +Просто в циклі перебираємо властивості об’єкта і повертаємо `false`, як тільки зустрічаємо властивість. \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/3-is-empty/task.md b/1-js/04-object-basics/01-object/3-is-empty/task.md index c438d36a2..de8690114 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/task.md +++ b/1-js/04-object-basics/01-object/3-is-empty/task.md @@ -2,18 +2,18 @@ importance: 5 --- -# Check for emptiness +# Перевірка на порожнечу -Write the function `isEmpty(obj)` which returns `true` if the object has no properties, `false` otherwise. +Напишіть функцію `isEmpty(obj)` яка повертає `true` якщо об’єкт не має властивості, інакше `false`. -Should work like that: +Має так працювати: ```js let schedule = {}; alert( isEmpty(schedule) ); // true -schedule["8:30"] = "get up"; +schedule["8:30"] = "Вставай"; alert( isEmpty(schedule) ); // false ``` diff --git a/1-js/04-object-basics/01-object/5-sum-object/task.md b/1-js/04-object-basics/01-object/5-sum-object/task.md index 7e3e048d0..c40290a71 100644 --- a/1-js/04-object-basics/01-object/5-sum-object/task.md +++ b/1-js/04-object-basics/01-object/5-sum-object/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# Sum object properties +# Сума властивостей об’єкта -We have an object storing salaries of our team: +У нас є об’єкт для зберігання заробітної плати нашої команди: ```js let salaries = { @@ -14,6 +14,6 @@ let salaries = { } ``` -Write the code to sum all salaries and store in the variable `sum`. Should be `390` in the example above. +Напишіть код для підсумовування всіх зарплат і збережіть у змінній `sum`. У наведеному вище прикладі має бути `390`. -If `salaries` is empty, then the result must be `0`. \ No newline at end of file +Якщо об’єкт `salaries` порожній, то результат має бути `0`. \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js index a02b1e1cb..0172b6120 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/source.js @@ -1,13 +1,13 @@ let menu = { width: 200, height: 300, - title: "My menu" + title: "Моє меню" }; function multiplyNumeric(obj) { - /* your code */ + /* ваш код */ } diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js index 064e5414f..f39ee6f35 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js @@ -1,18 +1,18 @@ -describe("multiplyNumeric", function() { - it("multiplies all numeric properties by 2", function() { +describe("помножимоЧисла", function () { + it("помножити всі числові властивості на 2", function () { let menu = { width: 200, height: 300, - title: "My menu" + title: "Моє меню" }; let result = multiplyNumeric(menu); assert.equal(menu.width, 400); assert.equal(menu.height, 600); - assert.equal(menu.title, "My menu"); + assert.equal(menu.title, "Моє меню"); }); - it("returns nothing", function() { - assert.isUndefined( multiplyNumeric({}) ); + it("нічого не повертає", function () { + assert.isUndefined(multiplyNumeric({})); }); }); diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md index 6878ca088..d39068130 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/task.md +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/task.md @@ -2,32 +2,32 @@ importance: 3 --- -# Multiply numeric property values by 2 +# Помножте числові значення властивостей на 2 -Create a function `multiplyNumeric(obj)` that multiplies all numeric property values of `obj` by `2`. +Створіть функцію `multiplyNumeric(obj)`, яка примножує всі числові властивості об’єкта `obj` на `2`. -For instance: +Наприклад: ```js -// before the call +// до виклику функції let menu = { width: 200, height: 300, - title: "My menu" + title: "Моє меню" }; multiplyNumeric(menu); -// after the call +// після виклику функції menu = { width: 400, height: 600, - title: "My menu" + title: "Моє меню" }; ``` -Please note that `multiplyNumeric` does not need to return anything. It should modify the object in-place. +Зверніть увагу, що `multiplyNumeric` не потрібно нічого повертати. Слід безпосередньо змінювати об’єкт. -P.S. Use `typeof` to check for a number here. +P.S. Використовуйте `typeof` для перевірки, що значення властивості числове. diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index ed8a3f4d7..872019836 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -1,60 +1,60 @@ -# Objects +# Об’єкти -As we know from the chapter , there are eight data types in JavaScript. Seven of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever). +Як ми знаємо з глави , у JavaScript є вісім типів даних. Сім з них називаються "примітивними", оскільки їх значення містять лише одну річ (будь то рядок, число чи щось інше). -In contrast, objects are used to store keyed collections of various data and more complex entities. In JavaScript, objects penetrate almost every aspect of the language. So we must understand them first before going in-depth anywhere else. +На противагу цьому, об’єкти використовуються для зберігання ключів різних колекцій даних та складніших об’єктів. У JavaScript об’єкти проникають майже в усі аспекти мови. Тому ми повинні їх спочатку зрозуміти, перш ніж заглиблюватися в складніші теми. -An object can be created with figure brackets `{…}` with an optional list of *properties*. A property is a "key: value" pair, where `key` is a string (also called a "property name"), and `value` can be anything. +Об’єкт можна створити за допомогою фігурних дужок `{…}` з необов’язковим списком *властивостей*. Властивість -- це пара "ключ: значення", де `ключ` -- це рядок (також називається "ім’я властивості"), а `значення` може бути будь-яким. -We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by the key. It's easy to find a file by its name or add/remove a file. +Ми можемо уявити собі об’єкт як шафу з підписаними файлами. Кожен фрагмент даних зберігається у своєму файлі за допомогою ключа. Легко знайти файл за назвою або додати/видалити файл. ![](object.svg) -An empty object ("empty cabinet") can be created using one of two syntaxes: +Порожній об’єкт ("порожню шафу") можна створити за допомогою одного з двох синтаксисів: ```js -let user = new Object(); // "object constructor" syntax -let user = {}; // "object literal" syntax +let user = new Object(); // синтаксис "конструктора об’єктів" +let user = {}; // синтаксис "літералу об’єкта" ``` ![](object-user-empty.svg) -Usually, the figure brackets `{...}` are used. That declaration is called an *object literal*. +Зазвичай використовуються фігурні дужки `{...}`. Таке оголошення називається *літералом об’єкта*. -## Literals and properties +## Літерали та властивості -We can immediately put some properties into `{...}` as "key: value" pairs: +Ми можемо одразу помістити деякі властивості у `{...}` як пари "ключ: значення": ```js -let user = { // an object - name: "John", // by key "name" store value "John" - age: 30 // by key "age" store value 30 +let user = { // об’єкт + name: "Іван", // за ключем "name" зберігаємо значення "Іван" + age: 30 // за ключем "age" зберігати значення "30" }; ``` -A property has a key (also known as "name" or "identifier") before the colon `":"` and a value to the right of it. +Властивість має ключ (також відомий як "ім’я" або "ідентифікатор") перед двокрапкою `":"` і значення праворуч від нього. -In the `user` object, there are two properties: +В об’єкті `user` зараз знаходяться дві властивості: -1. The first property has the name `"name"` and the value `"John"`. -2. The second one has the name `"age"` and the value `30`. +1. Перша властивість з ім’ям `"name"` і значенням `"Іван"`. +2. Друга властивість з ім’ям `"age"` і значенням `30`. -The resulting `user` object can be imagined as a cabinet with two signed files labeled "name" and "age". +Отриманий об’єкт `user` можна уявити собі як шафу з двома підписаними файлами з позначками "name" та "age". ![user object](object-user.svg) -We can add, remove and read files from it any time. +Ми можемо в будь-який момент додати в нього нові файли, видалити файли або прочитати вміст будь-якого файлу. -Property values are accessible using the dot notation: +Для звернення до властивостей використовується запис через крапку: ```js -// get property values of the object: -alert( user.name ); // John +// отримаємо значення властивостей об’єкта: +alert( user.name ); // Іван alert( user.age ); // 30 ``` -The value can be of any type. Let's add a boolean one: +Значення може бути будь-якого типу. Додамо булеве значення: ```js user.isAdmin = true; @@ -62,7 +62,7 @@ user.isAdmin = true; ![user object 2](object-user-isadmin.svg) -To remove a property, we can use `delete` operator: +Щоб видалити властивість ми можемо використовувати оператор `delete`: ```js delete user.age; @@ -70,88 +70,88 @@ delete user.age; ![user object 3](object-user-delete.svg) -We can also use multiword property names, but then they must be quoted: +Ім’я властивості може складатися з декількох слів, але тоді воно має бути поміщено в лапки: ```js let user = { - name: "John", + name: "Іван", age: 30, - "likes birds": true // multiword property name must be quoted + "likes birds": true // Ім’я властивості з декількох слів повинно бути в лапках }; ``` ![](object-user-props.svg) -The last property in the list may end with a comma: +Остання властивість у списку може закінчуватися комою: ```js let user = { - name: "John", + name: "Іван", age: 30*!*,*/!* } ``` -That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike. +Це називається "кінцевою" або "висячою" комою. Полегшує додавання/видалення/переміщення по властивостях, оскільки всі рядки стають однаковими. -## Square brackets +## Квадратні дужки -For multiword properties, the dot access doesn't work: +Для властивостей, імена яких складаються з декількох слів, доступ до значення «через крапку» не працює: ```js run -// this would give a syntax error +// це викличе синтаксичну помилку user.likes birds = true ``` -JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`. +JavaScript бачить, що ми звертаємося до властивості `user.likes`, а потім йде незрозуміле слово `birds`. В результаті отримаємо синтаксичну помилку. -The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn't start with a digit and doesn't include special characters (`$` and `_` are allowed). +Крапка вимагає, щоб ключ був правильним ідентифікатором змінної. Це означає: не містить пробілів, не починається з цифри та не містить спеціальних символів (`$` та `_` дозволені). -There's an alternative "square bracket notation" that works with any string: +Для таких випадків існує альтернативний спосіб доступу до властивостей через квадратні дужки. Такий спосіб спрацює з будь-яким ім’ям властивості: ```js run let user = {}; -// set -user["likes birds"] = true; +// присвоювання значення властивості +user["любить птахів"] = true; -// get -alert(user["likes birds"]); // true +// отримання значення властивості +alert (user["любить птахів"]); // true -// delete -delete user["likes birds"]; +// видалення властивості +delete user["любить птахів"]; ``` -Now everything is fine. Please note that the string inside the brackets is properly quoted (any type of quotes will do). +Зараз усе гаразд. Зверніть увагу, що рядок у квадратних дужках міститься в лапках (підійде будь-який тип лапок). -Square brackets also provide a way to obtain the property name as the result of any expression -- as opposed to a literal string -- like from a variable as follows: +Квадратні дужки також дозволяють звернутися до властивості, ім’я якої може бути результатом виразу. Наприклад, ім'я властивості може зберігатися в змінній: ```js -let key = "likes birds"; +let key = "любить птахів"; -// same as user["likes birds"] = true; +// так само, як user["любить птахів"] = true; user[key] = true; ``` -Here, the variable `key` may be calculated at run-time or depend on the user input. And then we use it to access the property. That gives us a great deal of flexibility. +Тут змінна `key` може бути обчислена під час виконання або залежатиме від вводу користувача. І тоді ми використовуємо його для доступу до властивості. Це дає нам велику гнучкість. -For instance: +Приклад: ```js run let user = { - name: "John", + name: "Іван", age: 30 }; -let key = prompt("What do you want to know about the user?", "name"); +let key = prompt("Що ви хочете знати про користувача?", "name"); -// access by variable -alert( user[key] ); // John (if enter "name") +// доступ до властивості через змінну +alert( user[key] ); // Іван (якщо ввести "name") ``` -The dot notation cannot be used in a similar way: +Запис «через крапку» такого не дозволяє: ```js run let user = { - name: "John", + name: "Іван", age: 30 }; @@ -159,40 +159,40 @@ let key = "name"; alert( user.key ) // undefined ``` -### Computed properties +### Обчислювані властивості -We can use square brackets in an object literal, when creating an object. That's called *computed properties*. +Ми можемо використовувати квадратні дужки в літеральній нотації для створення обчислюваної властивості. -For instance: +Наприклад: ```js run -let fruit = prompt("Which fruit to buy?", "apple"); +let fruit = prompt("Які фрукти купити?", "apple"); let bag = { *!* - [fruit]: 5, // the name of the property is taken from the variable fruit + [fruit]: 5, // назву властивості взято зі змінної fruit */!* }; -alert( bag.apple ); // 5 if fruit="apple" +alert( bag.apple ); // 5 якщо fruit="apple" ``` -The meaning of a computed property is simple: `[fruit]` means that the property name should be taken from `fruit`. +Значення обчислюваної властивості просте: `[fruit]` означає, що назву властивості слід брати з `fruit`. -So, if a visitor enters `"apple"`, `bag` will become `{apple: 5}`. +І якщо відвідувач введе слово `"apple"`, то в об’єкті `bag` тепер буде лежати властивість `{apple: 5}`. -Essentially, that works the same as: +По суті, це працює так само, як: ```js run -let fruit = prompt("Which fruit to buy?", "apple"); +let fruit = prompt("Які фрукти купити?", "apple"); let bag = {}; -// take property name from the fruit variable +// назву властивості взято зі змінної fruit bag[fruit] = 5; ``` -...But looks nicer. +... Але виглядає приємніше. -We can use more complex expressions inside square brackets: +Ми можемо використати більш складні вирази в квадратних дужках: ```js let fruit = 'apple'; @@ -201,63 +201,63 @@ let bag = { }; ``` -Square brackets are much more powerful than the dot notation. They allow any property names and variables. But they are also more cumbersome to write. +Квадратні дужки набагато потужніші за крапкову нотацію. Вони допускають будь-які назви властивостей та змінні. Але вони також більш громіздкі для написання. -So most of the time, when property names are known and simple, the dot is used. And if we need something more complex, then we switch to square brackets. +Тому більшість часу, коли назви властивостей відомі та прості, використовується крапка. А якщо нам потрібно щось складніше, то переходимо до квадратних дужок. -## Property value shorthand +## Властивість з змінної -In real code we often use existing variables as values for property names. +У реальному коді ми часто використовуємо наявні змінні як значення для імен властивостей. -For instance: +Приклад: ```js run function makeUser(name, age) { return { name: name, age: age, - // ...other properties + // ...інші властивості }; } -let user = makeUser("John", 30); -alert(user.name); // John +let user = makeUser("Іван", 30); +alert(user.name); // Іван ``` -In the example above, properties have the same names as variables. The use-case of making a property from a variable is so common, that there's a special *property value shorthand* to make it shorter. +В наведеному вище прикладі назва властивостей `name` і `age` збігаються з назвами змінних, які ми підставляємо в якості значень цих властивостей. Такий підхід настільки поширений, що існують спеціальні *короткі властивості* для спрощення цього запису. -Instead of `name:name` we can just write `name`, like this: +Замість `name: name` ми можемо написати просто `name`: ```js function makeUser(name, age) { *!* return { - name, // same as name: name - age, // same as age: age + name, // те ж саме, що name: name + age, // те ж саме, що age: age // ... }; */!* } ``` -We can use both normal properties and shorthands in the same object: +Ми можемо використовувати як звичайні властивості, так і скорочення в одному об’єкті: ```js let user = { - name, // same as name:name + name, // те ж саме, що name:name age: 30 }; ``` -## Property names limitations +## Обмеження для імен властивостей -As we already know, a variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc. +Як ми вже знаємо, змінна не може мати ім’я, рівне одному зі слів, зарезервованих мовою, як-от "for", "let", "return" тощо. -But for an object property, there's no such restriction: +То для властивості об’єкта немає такого обмеження: ```js run -// these properties are all right +// ці назви властивостей -- правильні let obj = { for: 1, let: 2, @@ -267,142 +267,142 @@ let obj = { alert( obj.for + obj.let + obj.return ); // 6 ``` -In short, there are no limitations on property names. They can be any strings or symbols (a special type for identifiers, to be covered later). +Коротко кажучи, немає ніяких обмежень щодо назв властивостей. Це можуть бути будь-які рядки або символи (спеціальний тип для ідентифікаторів, про які буде сказано пізніше). -Other types are automatically converted to strings. +Інші типи автоматично перетворюються на рядки. -For instance, a number `0` becomes a string `"0"` when used as a property key: +Наприклад, число `0` стає рядком `"0"`, коли використовується як ключ властивості: ```js run let obj = { - 0: "test" // same as "0": "test" + 0: "тест" // те ж саме, що "0": "тест" }; -// both alerts access the same property (the number 0 is converted to string "0") -alert( obj["0"] ); // test -alert( obj[0] ); // test (same property) +// обидва попередження мають доступ до однієї властивості (число 0 перетворюється на рядок "0") +alert( obj["0"] ); // тест +alert( obj[0] ); // тест (таж сама властивість) ``` -There's a minor gotcha with a special property named `__proto__`. We can't set it to a non-object value: +Є невеликий підводний камінь, пов’язаний зі спеціальною властивістю `__proto__`. Ми можемо встановити в нього значення об’єктного типу: ```js run let obj = {}; -obj.__proto__ = 5; // assign a number -alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended +obj.__proto__ = 5; // присвоїмо число +alert(obj.__proto__); // [object Object] - значення -- це об’єкт, тобто не те, що ми очікували ``` -As we see from the code, the assignment to a primitive `5` is ignored. +Як ми бачимо з коду, присвоєння числа `5` ігнорується. -We'll cover the special nature of `__proto__` in [subsequent chapters](info:prototype-inheritance), and suggest the [ways to fix](info:prototype-methods) such behavior. +Ми розглянемо особливий характер `__proto__` у [наступних розділах](info:prototype-inheritance) і запропонуємо [способи виправлення](info:prototype-methods) такої поведінки. -## Property existence test, "in" operator +## Перевірка існування властивості, оператор "in" -A notable feature of objects in JavaScript, compared to many other languages, is that it's possible to access any property. There will be no error if the property doesn't exist! +Помітною особливістю об’єктів у JavaScript, у порівнянні з багатьма іншими мовами, є можливість доступу до будь-якої властивості. Помилки не буде, якщо властивості не існує! -Reading a non-existing property just returns `undefined`. So we can easily test whether the property exists: +Читання відсутньої властивості просто повертає `undefined`. Тому ми можемо легко перевірити, чи існує властивість: ```js run let user = {}; -alert( user.noSuchProperty === undefined ); // true means "no such property" +alert( user.noSuchProperty === undefined ); // true означає "такої властивості немає" ``` -There's also a special operator `"in"` for that. +Для цього також є спеціальний оператор `"in"`. -The syntax is: +Синтаксис такий: ```js "key" in object ``` -For instance: +Наприклад: ```js run -let user = { name: "John", age: 30 }; +let user = { name: "Іван", age: 30 }; -alert( "age" in user ); // true, user.age exists -alert( "blabla" in user ); // false, user.blabla doesn't exist +alert( "age" in user ); // true, user.age існує +alert( "blabla" in user ); // false, user.blabla не існує ``` -Please note that on the left side of `in` there must be a *property name*. That's usually a quoted string. +Зверніть увагу, що зліва від оператора `in` повинно бути ім’я властивості. Зазвичай це рядок в лапках. -If we omit quotes, that means a variable, it should contain the actual name to be tested. For instance: +Якщо ми опускаємо лапки, це означає, що ми вказуємо змінну, в якій знаходиться ім'я властивості. Наприклад: ```js run let user = { age: 30 }; let key = "age"; -alert( *!*key*/!* in user ); // true, property "age" exists +alert( *!*key*/!* in user ); // true, властивість "age" існує ``` -Why does the `in` operator exist? Isn't it enough to compare against `undefined`? +Для чого взагалі потрібен оператор `in`? Хіба недостатньо порівняння з `undefined`? -Well, most of the time the comparison with `undefined` works fine. But there's a special case when it fails, but `"in"` works correctly. +У більшості випадків прекрасно спрацює порівняння з `undefined`. Але є особливий випадок, коли воно не підходить, і потрібно використовувати `"in"`. -It's when an object property exists, but stores `undefined`: +Це коли властивість існує, але містить значення `undefined`: ```js run let obj = { test: undefined }; -alert( obj.test ); // it's undefined, so - no such property? +alert( obj.test ); // виведеться undefined, значить властивість не існує? -alert( "test" in obj ); // true, the property does exist! +alert( "test" in obj ); // true, властивість існує! ``` -In the code above, the property `obj.test` technically exists. So the `in` operator works right. +У наведеному вище коді властивість `obj.test` технічно існує. Отже, оператор `in` працює правильно. -Situations like this happen very rarely, because `undefined` should not be explicitly assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code. +Такі ситуації трапляються дуже рідко, тому що `undefined` не слід чітко призначати. Ми в основному використовуємо `null` для "невідомих" або "порожніх" значень. Отже, оператор `in` -- екзотичний гість у коді. -## The "for..in" loop +## Цикл "for..in" -To walk over all keys of an object, there exists a special form of the loop: `for..in`. This is a completely different thing from the `for(;;)` construct that we studied before. +Для перебору всіх властивостей об’єкта використовується цикл `for..in`. Цей цикл відрізняється від вивченого раніше циклу `for(;;)`. -The syntax: +Синтаксис: ```js for (key in object) { - // executes the body for each key among object properties + // тіло циклу виконується для кожної властивості об’єкта } ``` -For instance, let's output all properties of `user`: +Наприклад, виведемо всі властивості `user`: ```js run let user = { - name: "John", + name: "Іван", age: 30, isAdmin: true }; for (let key in user) { - // keys + // ключі alert( key ); // name, age, isAdmin - // values for the keys - alert( user[key] ); // John, 30, true + // значення ключів + alert( user[key] ); // Іван, 30, true } ``` -Note that all "for" constructs allow us to declare the looping variable inside the loop, like `let key` here. +Зверніть увагу, що всі конструкції "for" дозволяють нам оголошувати змінну всередині циклу, як, наприклад, `let key` тут. -Also, we could use another variable name here instead of `key`. For instance, `"for (let prop in obj)"` is also widely used. +Крім того, ми могли б використовувати інше ім’я змінної. Наприклад, часто використовується варіант `"for (let prop in obj)"`. -### Ordered like an object +### Впорядкування властивостей об’єкта -Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this? +Чи упорядковані властивості об’єкта? Іншими словами, якщо ми будемо в циклі перебирати всі властивості об’єкта, чи отримаємо ми їх в тому ж порядку, в якому ми їх додавали? Чи можемо ми на це розраховувати? -The short answer is: "ordered in a special fashion": integer properties are sorted, others appear in creation order. The details follow. +Коротка відповідь: "властивості впорядковані особливим чином". Властивості з цілочисельними ключами сортуються за зростанням, інші розташовуються в порядку створення. Розберемося докладніше. -As an example, let's consider an object with the phone codes: +Як приклад розглянемо об’єкт з телефонними кодами: ```js run -let codes = { - "49": "Germany", - "41": "Switzerland", - "44": "Great Britain", - // .., - "1": "USA" +let codes ={ + "49": "Німеччина", + "41": "Швейцарія", + "44": "Великобританія", + // .., + "1": "США" }; *!* @@ -412,48 +412,48 @@ for (let code in codes) { */!* ``` -The object may be used to suggest a list of options to the user. If we're making a site mainly for German audience then we probably want `49` to be the first. +Якщо ми робимо сайт для німецької аудиторії, то, ймовірно, ми хочемо, щоб код `49` був першим. -But if we run the code, we see a totally different picture: +Але якщо ми запустимо код, ми побачимо зовсім іншу картину: -- USA (1) goes first -- then Switzerland (41) and so on. +- США (1) йде першим +- потім Швейцарія (41) і так далі. -The phone codes go in the ascending sorted order, because they are integers. So we see `1, 41, 44, 49`. +Телефонні коди йдуть в порядку зростання, тому що вони є цілими числами: `1, 41, 44, 49`. -````smart header="Integer properties? What's that?" -The "integer property" term here means a string that can be converted to-and-from an integer without a change. +````smart header="Цілочисельні властивості? Що це?" +Термін "цілочисельна властивість" означає рядок, який може бути перетворений в ціле число і назад без змін. -So, "49" is an integer property name, because when it's transformed to an integer number and back, it's still the same. But "+49" and "1.2" are not: +Тобто, "49" -- це цілочисельне ім'я властивості, тому що якщо його перетворити в ціле число, а потім назад в рядок, то воно не зміниться. А ось властивості "+49" або "1.2" такими не є: ```js run -// Math.trunc is a built-in function that removes the decimal part -alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property -alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property -alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property +// Math.trunc -- вбудована функція, яка видаляє десяткову частину +alert( String( Math.trunc( Number("49"))) ); // "49", те ж саме ⇒ властивість цілочисельна +alert( String( Math.trunc( Number("+49"))) ); // "49", не те ж саме, що "+49" ⇒ властивість не цілочисельна +alert( String( Math.trunc( Number("1.2")))); // "1", не те ж саме, що "1.2" ⇒ властивість не цілочисельна ``` ```` -...On the other hand, if the keys are non-integer, then they are listed in the creation order, for instance: +...З іншого боку, якщо ключ не цілочисельний, то вони перебираються в порядку створення, наприклад: ```js run let user = { - name: "John", + name: "Іван", surname: "Smith" }; -user.age = 25; // add one more +user.age = 25; // добавимо ще одну властивість *!* -// non-integer properties are listed in the creation order +// не цілочисельні властивості перераховані в порядку створення */!* for (let prop in user) { alert( prop ); // name, surname, age } ``` -So, to fix the issue with the phone codes, we can "cheat" by making the codes non-integer. Adding a plus `"+"` sign before each code is enough. +Таким чином, щоб вирішити нашу проблему з телефонними кодами, ми можемо схитрувати, зробивши коди не цілочисельними властивостями. Додамо знак `"+"` перед кожним кодом. -Like this: +Приклад: ```js run let codes = { @@ -469,34 +469,34 @@ for (let code in codes) { } ``` -Now it works as intended. +Зараз скрипт працює, як передбачалося. -## Summary +## Висновок -Objects are associative arrays with several special features. +Об’єкти -- це асоціативні масиви з рядом додаткових можливостей. -They store properties (key-value pairs), where: -- Property keys must be strings or symbols (usually strings). -- Values can be of any type. +Вони зберігають властивості (пари ключ-значення), де: +- Ключі властивостей повинні бути рядками або символами (зазвичай рядками). +- Значення можуть бути будь-якого типу. -To access a property, we can use: -- The dot notation: `obj.property`. -- Square brackets notation `obj["property"]`. Square brackets allow to take the key from a variable, like `obj[varWithKey]`. +Щоб отримати доступ до властивості, ми можемо використовувати: +- Запис через крапку: `obj.property`. +- Квадратні дужки `obj["property"]`. Квадратні дужки дозволяють взяти ключ з змінної, наприклад, `obj[varWithKey]`. -Additional operators: -- To delete a property: `delete obj.prop`. -- To check if a property with the given key exists: `"key" in obj`. -- To iterate over an object: `for (let key in obj)` loop. +Додаткові оператори: +- Видалення властивості: `delete obj.prop`. +- Перевірка існування властивості: `"key" in obj`. +- Перебір властивостей об’єкта: цикл `for for (let key in obj)`. -What we've studied in this chapter is called a "plain object", or just `Object`. +Те, що ми вивчали в цьому розділі, називається "простим об’єктом" або просто `Object`. -There are many other kinds of objects in JavaScript: +В JavaScript є багато інших типів об’єктів: -- `Array` to store ordered data collections, -- `Date` to store the information about the date and time, -- `Error` to store the information about an error. -- ...And so on. +- `Array` для зберігання впорядкованих колекцій даних, +- `Date` для зберігання інформації про дату і час, +- `Error` для зберігання інформації про помилку. +- … і так далі. -They have their special features that we'll study later. Sometimes people say something like "Array type" or "Date type", but formally they are not types of their own, but belong to a single "object" data type. And they extend it in various ways. +У них є свої особливості, які ми вивчимо пізніше. Іноді люди говорять щось на кшталт "тип даних Array" або "тип даних Date", але формально вони не є окремими типами, а належать до типу даних `"Object"`. Вони лише розширюють його різними способами. -Objects in JavaScript are very powerful. Here we've just scratched the surface of a topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. +Об’єкти в JavaScript дуже потужні. Тут ми тільки трохи заглибилися в дійсно величезну тему. Ми будемо тісно працювати з об’єктами і дізнаємося про них більше в наступних частинах підручника. From 6f63dffd86e65b1a24adb235433136c7200eca6b Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Sun, 15 Aug 2021 21:59:32 +0300 Subject: [PATCH 02/27] Update 1-js/04-object-basics/01-object/2-hello-object/task.md Co-authored-by: Taras --- 1-js/04-object-basics/01-object/2-hello-object/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index fe5f738e5..0eec61f8b 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -7,7 +7,7 @@ importance: 5 Напишіть код, виконавши завдання з кожного пункту окремим рядком: 1. Створіть порожній об’єкт `user`. -2. Додайте властивість `ім’я` зі значенням `Іван`. +2. Додайте властивість `name` зі значенням `Іван`. 3. Додайте властивість `прізвище` зі значенням `Сміт`. 4. Змініть значення `ім’я` на `Петро`. 5. Видаліть властивість `ім’я` з об’єкта. From 690516f04ff4030457ebac6c0e3472a1d7122aac Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Sun, 15 Aug 2021 21:59:44 +0300 Subject: [PATCH 03/27] Update 1-js/04-object-basics/01-object/3-is-empty/task.md Co-authored-by: Taras --- 1-js/04-object-basics/01-object/3-is-empty/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/3-is-empty/task.md b/1-js/04-object-basics/01-object/3-is-empty/task.md index de8690114..015b7249f 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/task.md +++ b/1-js/04-object-basics/01-object/3-is-empty/task.md @@ -4,7 +4,7 @@ importance: 5 # Перевірка на порожнечу -Напишіть функцію `isEmpty(obj)` яка повертає `true` якщо об’єкт не має властивості, інакше `false`. +Напишіть функцію `isEmpty(obj)`, яка повертає `true`, якщо об’єкт не має властивості, інакше `false`. Має так працювати: From d1d20f9bd2e13b28c59ce8720b418dc630ffdd5a Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Sun, 15 Aug 2021 21:59:52 +0300 Subject: [PATCH 04/27] Update 1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js Co-authored-by: Taras --- .../01-object/8-multiply-numeric/_js.view/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js index f39ee6f35..956185233 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js @@ -1,4 +1,4 @@ -describe("помножимоЧисла", function () { +describe("multiplyNumeric", function () { it("помножити всі числові властивості на 2", function () { let menu = { width: 200, From 126b55be31360afd70724178a8f4bbd7b446b04e Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Sun, 15 Aug 2021 22:00:13 +0300 Subject: [PATCH 05/27] Update 1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js Co-authored-by: Taras --- .../01-object/8-multiply-numeric/_js.view/test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js index 956185233..d9c8b76ec 100644 --- a/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js +++ b/1-js/04-object-basics/01-object/8-multiply-numeric/_js.view/test.js @@ -1,5 +1,5 @@ describe("multiplyNumeric", function () { - it("помножити всі числові властивості на 2", function () { + it("множить всі числові властивості на 2", function () { let menu = { width: 200, height: 300, From 1808c2fa51958c361667dc5f7901916c0e928007 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Sun, 15 Aug 2021 22:00:41 +0300 Subject: [PATCH 06/27] Update 1-js/04-object-basics/01-object/article.md Co-authored-by: Taras --- 1-js/04-object-basics/01-object/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 872019836..8315a83a6 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -1,7 +1,7 @@ # Об’єкти -Як ми знаємо з глави , у JavaScript є вісім типів даних. Сім з них називаються "примітивними", оскільки їх значення містять лише одну річ (будь то рядок, число чи щось інше). +Як ми знаємо з глави , у JavaScript є вісім типів даних. Сім з них називаються "примітивними", оскільки їх значення містять лише одну річ (чи то рядок, число чи щось інше). На противагу цьому, об’єкти використовуються для зберігання ключів різних колекцій даних та складніших об’єктів. У JavaScript об’єкти проникають майже в усі аспекти мови. Тому ми повинні їх спочатку зрозуміти, перш ніж заглиблюватися в складніші теми. From b7f47463afb033c1ea4b2ea0b76ab2eb781e3628 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Sun, 15 Aug 2021 22:01:20 +0300 Subject: [PATCH 07/27] Update 1-js/04-object-basics/01-object/article.md Co-authored-by: Taras --- 1-js/04-object-basics/01-object/article.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 8315a83a6..ab85b328c 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -114,7 +114,7 @@ let user = {}; user["любить птахів"] = true; // отримання значення властивості -alert (user["любить птахів"]); // true +alert(user["любить птахів"]); // true // видалення властивості delete user["любить птахів"]; From c31ff51b4e19684c626a677653096c6c55f40b66 Mon Sep 17 00:00:00 2001 From: Taras Date: Sun, 15 Aug 2021 22:10:14 +0300 Subject: [PATCH 08/27] Update 1-js/04-object-basics/01-object/2-hello-object/task.md --- 1-js/04-object-basics/01-object/2-hello-object/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index 0eec61f8b..a3ed1b602 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -8,7 +8,7 @@ importance: 5 1. Створіть порожній об’єкт `user`. 2. Додайте властивість `name` зі значенням `Іван`. -3. Додайте властивість `прізвище` зі значенням `Сміт`. +3. Додайте властивість `surname` зі значенням `Сміт`. 4. Змініть значення `ім’я` на `Петро`. 5. Видаліть властивість `ім’я` з об’єкта. From 68d53ebd0bf3199d4176a97dc8933bc32e7a4191 Mon Sep 17 00:00:00 2001 From: Taras Date: Sun, 15 Aug 2021 22:10:43 +0300 Subject: [PATCH 09/27] Update 1-js/04-object-basics/01-object/2-hello-object/task.md --- 1-js/04-object-basics/01-object/2-hello-object/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index a3ed1b602..d1ae5a604 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -10,5 +10,5 @@ importance: 5 2. Додайте властивість `name` зі значенням `Іван`. 3. Додайте властивість `surname` зі значенням `Сміт`. 4. Змініть значення `ім’я` на `Петро`. -5. Видаліть властивість `ім’я` з об’єкта. +5. Видаліть властивість `name` з об’єкта. From 019602eec5b9b7fb6a78617af041b80923a65dec Mon Sep 17 00:00:00 2001 From: Taras Date: Sun, 15 Aug 2021 22:10:48 +0300 Subject: [PATCH 10/27] Update 1-js/04-object-basics/01-object/2-hello-object/task.md --- 1-js/04-object-basics/01-object/2-hello-object/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/04-object-basics/01-object/2-hello-object/task.md b/1-js/04-object-basics/01-object/2-hello-object/task.md index d1ae5a604..720e5b95f 100644 --- a/1-js/04-object-basics/01-object/2-hello-object/task.md +++ b/1-js/04-object-basics/01-object/2-hello-object/task.md @@ -9,6 +9,6 @@ importance: 5 1. Створіть порожній об’єкт `user`. 2. Додайте властивість `name` зі значенням `Іван`. 3. Додайте властивість `surname` зі значенням `Сміт`. -4. Змініть значення `ім’я` на `Петро`. +4. Змініть значення `name` на `Петро`. 5. Видаліть властивість `name` з об’єкта. From 550b1fb58cce4d0ad5deb97f4c8a1002a31a4f4c Mon Sep 17 00:00:00 2001 From: regnised Date: Mon, 23 Aug 2021 13:09:48 +0300 Subject: [PATCH 11/27] Objects --- .../1-camelcase/_js.view/solution.js | 8 +- .../05-array-methods/1-camelcase/task.md | 10 +- .../10-average-age/solution.md | 8 +- .../05-array-methods/10-average-age/task.md | 8 +- .../11-array-unique/solution.md | 28 +- .../05-array-methods/11-array-unique/task.md | 16 +- .../05-array-methods/12-reduce-object/task.md | 16 +- .../2-filter-range/_js.view/solution.js | 2 +- .../2-filter-range/solution.md | 6 +- .../05-array-methods/2-filter-range/task.md | 12 +- .../3-filter-range-in-place/solution.md | 4 +- .../3-filter-range-in-place/task.md | 10 +- .../05-array-methods/4-sort-back/task.md | 4 +- .../5-copy-sort-array/solution.md | 2 +- .../5-copy-sort-array/task.md | 8 +- .../6-array-get-names/solution.md | 10 +- .../6-array-get-names/task.md | 18 +- .../6-calculator-extendable/solution.md | 4 +- .../6-calculator-extendable/task.md | 20 +- .../7-map-objects/solution.md | 26 +- .../05-array-methods/7-map-objects/task.md | 28 +- .../8-sort-objects/solution.md | 16 +- .../05-array-methods/8-sort-objects/task.md | 22 +- .../05-array-methods/9-shuffle/solution.md | 44 +- .../05-array-methods/9-shuffle/task.md | 8 +- .../05-data-types/05-array-methods/article.md | 500 +++++++++--------- 26 files changed, 419 insertions(+), 419 deletions(-) diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js index 490f570ad..5ae73335a 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js @@ -1,10 +1,10 @@ function camelize(str) { return str - .split('-') // splits 'my-long-word' into array ['my', 'long', 'word'] + .split('-') // розбиваємо 'my-long-word' на масив елементів ['my', 'long', 'word'] .map( - // capitalizes first letters of all array items except the first one - // converts ['my', 'long', 'word'] into ['my', 'Long', 'Word'] + // робимо першу літеру велику для всіх елементів масиву, крім першого + // конвертуємо ['my', 'long', 'word'] в ['my', 'Long', 'Word'] (word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1) ) - .join(''); // joins ['my', 'Long', 'Word'] into 'myLongWord' + .join(''); // зʼєднуємо ['my', 'Long', 'Word'] в 'myLongWord' } diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/task.md b/1-js/05-data-types/05-array-methods/1-camelcase/task.md index ef5944636..adccc5392 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/task.md +++ b/1-js/05-data-types/05-array-methods/1-camelcase/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# Translate border-left-width to borderLeftWidth +# Переведіть текст виду border-left-width в borderLeftWidth -Write the function `camelize(str)` that changes dash-separated words like "my-short-string" into camel-cased "myShortString". +Напишіть функцію `camelize(str)`, яка перетворює такі рядки "my-short-string" в "myShortString". -That is: removes all dashes, each word after dash becomes uppercased. +Тобто дефіси видаляються, а всі слова після них починаються з великою літери. -Examples: +Приклади: ```js camelize("background-color") == 'backgroundColor'; @@ -16,4 +16,4 @@ camelize("list-style-image") == 'listStyleImage'; camelize("-webkit-transition") == 'WebkitTransition'; ``` -P.S. Hint: use `split` to split the string into an array, transform it and `join` back. +P.S. Підказка: використовуйте `split`, щоб розбити рядок на масив символів, потім переробіть все як потрібно та методом `join` зʼєднайте елементи в рядок. diff --git a/1-js/05-data-types/05-array-methods/10-average-age/solution.md b/1-js/05-data-types/05-array-methods/10-average-age/solution.md index f5d4df931..a3187922e 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/solution.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/solution.md @@ -3,11 +3,11 @@ function getAverageAge(users) { return users.reduce((prev, user) => prev + user.age, 0) / users.length; } -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 29 }; +let ivan = { name: "Іван", age: 25 }; +let petro = { name: "Петро", age: 30 }; +let mariya = { name: "Марія", age: 29 }; -let arr = [ john, pete, mary ]; +let arr = [ ivan, petro, mariya ]; alert( getAverageAge(arr) ); // 28 ``` diff --git a/1-js/05-data-types/05-array-methods/10-average-age/task.md b/1-js/05-data-types/05-array-methods/10-average-age/task.md index bf5f85df3..caa601064 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/task.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/task.md @@ -2,13 +2,13 @@ importance: 4 --- -# Get average age +# Вирахувати середній вік -Write the function `getAverageAge(users)` that gets an array of objects with property `age` and returns the average age. +Напишіть функцію `getAverageAge(users)`, яка приймає масив об’єктів з властивістю `age` та повертає середній вік. -The formula for the average is `(age1 + age2 + ... + ageN) / N`. +Формула обчислення середнього арифметичного значення: `(age1 + age2 + ... + ageN) / N`. -For instance: +Наприклад: ```js no-beautify let john = { name: "John", age: 25 }; diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md index b9d627a0a..c2da540c1 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md +++ b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md @@ -1,6 +1,6 @@ -Let's walk the array items: -- For each item we'll check if the resulting array already has that item. -- If it is so, then ignore, otherwise add to results. +Давайте пройдемося по елементам масиву: +- Для кожного елемента ми перевіримо, чи є він в масиві з результатом. +- Якщо є, то ігноруємо його, а якщо немає -- додаємо до результатів. ```js run demo function unique(arr) { @@ -15,25 +15,25 @@ function unique(arr) { return result; } -let strings = ["Hare", "Krishna", "Hare", "Krishna", - "Krishna", "Krishna", "Hare", "Hare", ":-O" +let strings = ["Привіт", "Світ", "Привіт", "Світ", + "Привіт", "Привіт", "Світ", "Світ", ":-O" ]; -alert( unique(strings) ); // Hare, Krishna, :-O +alert( unique(strings) ); // Привіт, Світ, :-O ``` -The code works, but there's a potential performance problem in it. +Код працює, але в ньому є потенційна проблема з продуктивністю. -The method `result.includes(str)` internally walks the array `result` and compares each element against `str` to find the match. +Метод `result.includes(str)` всередині себе обходить масив `result` і порівнює кожен елемент з `str`, щоб знайти збіг. -So if there are `100` elements in `result` and no one matches `str`, then it will walk the whole `result` and do exactly `100` comparisons. And if `result` is large, like `10000`, then there would be `10000` comparisons. +Таким чином, якщо `result` містить `100` елементів і жоден з них не збігається з `str`, тоді він обійде весь `result` і зробить рівно `100` порівнянь. А якщо `result` великий масив, наприклад, `10000` елементів, то буде зроблено `10000` порівнянь. -That's not a problem by itself, because JavaScript engines are very fast, so walk `10000` array is a matter of microseconds. +Само по собі це не проблема, тому що JavaScript двигун дуже швидкий, тому обхід `10000` елементів масиву займає лічені мікросекунди. -But we do such test for each element of `arr`, in the `for` loop. +Але ми робимо таку перевірку для кожного елемента `arr` в циклі `for`. -So if `arr.length` is `10000` we'll have something like `10000*10000` = 100 millions of comparisons. That's a lot. +Тому, якщо `arr.length` дорівнює `10000`, у нас буде щось на зразок `10000*10000` = 100 мільйонів порівнянь. Це забагато. -So the solution is only good for small arrays. +Ось чому дане рішення підходить тільки для невеликих масивів. -Further in the chapter we'll see how to optimize it. +Далі в розділі ми побачимо, як його оптимізувати. diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/task.md b/1-js/05-data-types/05-array-methods/11-array-unique/task.md index 5b56d3621..e32c3f782 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/task.md +++ b/1-js/05-data-types/05-array-methods/11-array-unique/task.md @@ -2,22 +2,22 @@ importance: 4 --- -# Filter unique array members +# Залишити унікальні елементи масиву -Let `arr` be an array. +Нехай `arr` -- масив рядків. -Create a function `unique(arr)` that should return an array with unique items of `arr`. +Напишіть функцію `unique(arr)`, яка повертає масив, що містить тільки унікальні елементи `arr`. -For instance: +Наприклад: ```js function unique(arr) { - /* your code */ + /* ваш код */ } -let strings = ["Hare", "Krishna", "Hare", "Krishna", - "Krishna", "Krishna", "Hare", "Hare", ":-O" +let strings = ["Привіт", "Світ", "Привіт", "Світ", + "Привіт", "Привіт", "Світ", "Світ", ":-O" ]; -alert( unique(strings) ); // Hare, Krishna, :-O +alert( unique(strings) ); // Привіт, Світ, :-O ``` diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md index 7f0082357..a0b5cbe56 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md @@ -2,13 +2,13 @@ importance: 4 --- -# Create keyed object from array +# Створення об'єкта з ключем з масиву -Let's say we received an array of users in the form `{id:..., name:..., age:... }`. +Припустимо, ми отримали масив користувачів у вигляді `{id:..., name:..., age:...}`. -Create a function `groupById(arr)` that creates an object from it, with `id` as the key, and array items as values. +Створіть функцію `groupById(arr)`, яка створює з масиву об’єкт із ключом `id` та елементами масиву як значеннями. -For example: +Наприклад: ```js let users = [ @@ -20,7 +20,7 @@ let users = [ let usersById = groupById(users); /* -// after the call we should have: +// після виклику функції ви повинні отримати: usersById = { john: {id: 'john', name: "John Smith", age: 20}, @@ -30,8 +30,8 @@ usersById = { */ ``` -Such function is really handy when working with server data. +Така функція дійсно зручна при роботі з даними сервера. -In this task we assume that `id` is unique. There may be no two array items with the same `id`. +У цьому завданні ми вважаємо, що `id` унікальний. Не може бути двох елементів масиву з однаковими `id`. -Please use array `.reduce` method in the solution. +Будь ласка, використовуйте метод масиву `.reduce` у рішенні. diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js b/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js index 0bdfbae5a..792c7b45e 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/2-filter-range/_js.view/solution.js @@ -1,5 +1,5 @@ function filterRange(arr, a, b) { - // added brackets around the expression for better readability + // навколо виразу додано дужки для кращої читабельності return arr.filter(item => (a <= item && item <= b)); } \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md index 73993a07a..9d48e6361 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md @@ -1,6 +1,6 @@ ```js run demo function filterRange(arr, a, b) { - // added brackets around the expression for better readability + // навколо виразу додано дужки для кращої читабельності return arr.filter(item => (a <= item && item <= b)); } @@ -8,7 +8,7 @@ let arr = [5, 3, 8, 1]; let filtered = filterRange(arr, 1, 4); -alert( filtered ); // 3,1 (matching values) +alert( filtered ); // 3,1 (відфільтровані значення) -alert( arr ); // 5,3,8,1 (not modified) +alert( arr ); // 5,3,8,1 (не змінюється) ``` diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/task.md b/1-js/05-data-types/05-array-methods/2-filter-range/task.md index 46e47c93d..d60c530d0 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/task.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/task.md @@ -2,21 +2,21 @@ importance: 4 --- -# Filter range +# Фільтрація за діапазоном -Write a function `filterRange(arr, a, b)` that gets an array `arr`, looks for elements with values higher or equal to `a` and lower or equal to `b` and return a result as an array. +Напишіть функцію `filterRange(arr, a, b)`, яка приймає масив `arr`, шукає в ньому елементи більші-рівні `a` та менші-рівні `b` і віддає масив цих елементів. -The function should not modify the array. It should return the new array. +Функція повинна повертати новий масив і не змінювати вихідний. -For instance: +Наприклад: ```js let arr = [5, 3, 8, 1]; let filtered = filterRange(arr, 1, 4); -alert( filtered ); // 3,1 (matching values) +alert( filtered ); // 3,1 (відфільтровані значення) -alert( arr ); // 5,3,8,1 (not modified) +alert( arr ); // 5,3,8,1 (не змінюється) ``` diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md index 36e3130ff..999c25465 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md @@ -4,7 +4,7 @@ function filterRangeInPlace(arr, a, b) { for (let i = 0; i < arr.length; i++) { let val = arr[i]; - // remove if outside of the interval + // видаляти, якщо не у вказаному діапазоні if (val < a || val > b) { arr.splice(i, 1); i--; @@ -15,7 +15,7 @@ function filterRangeInPlace(arr, a, b) { let arr = [5, 3, 8, 1]; -filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4 +filterRangeInPlace(arr, 1, 4); // видаляє всі числа крім тих, що в діапазоні від 1 до 4 alert( arr ); // [3, 1] ``` diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md index 7066a51ab..5fdee1aaf 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md @@ -2,17 +2,17 @@ importance: 4 --- -# Filter range "in place" +# Фільтрація за діапазоном "на місці" -Write a function `filterRangeInPlace(arr, a, b)` that gets an array `arr` and removes from it all values except those that are between `a` and `b`. The test is: `a ≤ arr[i] ≤ b`. +Напишіть функцію `filterRangeInPlace(arr, a, b)`, яка приймає масив `arr` і видаляє з нього всі значення крім тих, які знаходяться між `a` і `b`. Тобто, перевірка має вигляд `a ≤ arr [i] ≤ b`. -The function should only modify the array. It should not return anything. +Функція повинна змінювати поточний масив і нічого не повертати. -For instance: +Наприклад: ```js let arr = [5, 3, 8, 1]; -filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4 +filterRangeInPlace(arr, 1, 4); // видаляє всі числа крім тих, що в діапазоні від 1 до 4 alert( arr ); // [3, 1] ``` diff --git a/1-js/05-data-types/05-array-methods/4-sort-back/task.md b/1-js/05-data-types/05-array-methods/4-sort-back/task.md index 0e3eeab76..b446e98fc 100644 --- a/1-js/05-data-types/05-array-methods/4-sort-back/task.md +++ b/1-js/05-data-types/05-array-methods/4-sort-back/task.md @@ -2,12 +2,12 @@ importance: 4 --- -# Sort in decreasing order +# Сортувати за спаданням ```js let arr = [5, 2, 1, -10, 8]; -// ... your code to sort it in decreasing order +// ... ваш код для сортування за спаданням alert( arr ); // 8, 5, 2, 1, -10 ``` diff --git a/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md b/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md index 8537b129e..fc0926c9c 100644 --- a/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md +++ b/1-js/05-data-types/05-array-methods/5-copy-sort-array/solution.md @@ -1,4 +1,4 @@ -We can use `slice()` to make a copy and run the sort on it: +Для копіювання масиву використовуємо `slice()` і тут же -- сортування: ```js run function copySorted(arr) { diff --git a/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md b/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md index c1395b4ad..1cb0c1693 100644 --- a/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md +++ b/1-js/05-data-types/05-array-methods/5-copy-sort-array/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# Copy and sort array +# Скопіювати і впорядкувати масив -We have an array of strings `arr`. We'd like to have a sorted copy of it, but keep `arr` unmodified. +У нас є масив рядків `arr`. Потрібно отримати відсортовану копію та залишити `arr` незміненим. -Create a function `copySorted(arr)` that returns such a copy. +Створіть функцію `copySorted(arr)`, яка буде повертати таку копію. ```js let arr = ["HTML", "JavaScript", "CSS"]; @@ -14,5 +14,5 @@ let arr = ["HTML", "JavaScript", "CSS"]; let sorted = copySorted(arr); alert( sorted ); // CSS, HTML, JavaScript -alert( arr ); // HTML, JavaScript, CSS (no changes) +alert( arr ); // HTML, JavaScript, CSS (без змін) ``` diff --git a/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md b/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md index f44a2b812..8c745faf1 100644 --- a/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md +++ b/1-js/05-data-types/05-array-methods/6-array-get-names/solution.md @@ -1,13 +1,13 @@ ```js run -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let ivan = { name: "Іван", age: 25 }; +let petro = { name: "Петро", age: 30 }; +let mariya = { name: "Марія", age: 28 }; -let users = [ john, pete, mary ]; +let users = [ ivan, petro, mariya ]; let names = users.map(item => item.name); -alert( names ); // John, Pete, Mary +alert( names ); // Іван, Петро, Марія ``` diff --git a/1-js/05-data-types/05-array-methods/6-array-get-names/task.md b/1-js/05-data-types/05-array-methods/6-array-get-names/task.md index 74c8a9d74..3b4130f86 100644 --- a/1-js/05-data-types/05-array-methods/6-array-get-names/task.md +++ b/1-js/05-data-types/05-array-methods/6-array-get-names/task.md @@ -2,21 +2,21 @@ importance: 5 --- -# Map to names +# Трансформувати в масив імен -You have an array of `user` objects, each one has `user.name`. Write the code that converts it into an array of names. +У вас є масив об’єктів user, і в кожному з них є `user.name`. Напишіть код, який перетворює їх в масив імен. -For instance: +Наприклад: ```js no-beautify -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let ivan = { name: "Іван", age: 25 }; +let petro = { name: "Петро", age: 30 }; +let mariya = { name: "Марія", age: 28 }; -let users = [ john, pete, mary ]; +let users = [ ivan, petro, mariya ]; -let names = /* ... your code */ +let names = /* ... ваш код */ -alert( names ); // John, Pete, Mary +alert( names ); // Іван, Петро, Марія ``` diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md index ebe0714cf..b3a5ab5f7 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md @@ -1,3 +1,3 @@ -- Please note how methods are stored. They are simply added to `this.methods` property. -- All tests and numeric conversions are done in the `calculate` method. In future it may be extended to support more complex expressions. +- Зверніть увагу, як зберігаються методи. Вони просто додаються до внутрішнього обʼєкта (`this.methods`). +- Всі тести та числові перетворення виконуються в методі `calculate`. У майбутньому він може бути розширений для підтримки складніших виразів. diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md b/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md index e0d302f4c..83c14d3d2 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md @@ -2,24 +2,24 @@ importance: 5 --- -# Create an extendable calculator +# Створити розширюваний калькулятор -Create a constructor function `Calculator` that creates "extendable" calculator objects. +Створіть функцію-конструктор `Calculator`, яка створює «розширюваний» обʼєкт калькулятора. -The task consists of two parts. +Завдання складається з двох частин. -1. First, implement the method `calculate(str)` that takes a string like `"1 + 2"` in the format "NUMBER operator NUMBER" (space-delimited) and returns the result. Should understand plus `+` and minus `-`. +1. По-перше, реалізуйте метод `calculate(str)`, який приймає рядок типу `"1 + 2"` в форматі «ЧИСЛО оператор ЧИСЛО» (розділені пробілами) і повертає результат. Метод повинен розуміти плюс `+` і мінус `-`. - Usage example: + Приклад використання: ```js let calc = new Calculator; alert( calc.calculate("3 + 7") ); // 10 ``` -2. Then add the method `addMethod(name, func)` that teaches the calculator a new operation. It takes the operator `name` and the two-argument function `func(a,b)` that implements it. +2. Потім додайте метод `addMethod(name, func)`, який додає в калькулятор нові операції. Він приймає оператор `name` і функцію з двома аргументами `func(a, b)`, яка описує його. - For instance, let's add the multiplication `*`, division `/` and power `**`: + Наприклад, давайте додамо множення `*`, ділення `/` і зведення в ступінь `**`: ```js let powerCalc = new Calculator; @@ -31,6 +31,6 @@ The task consists of two parts. alert( result ); // 8 ``` -- No parentheses or complex expressions in this task. -- The numbers and the operator are delimited with exactly one space. -- There may be error handling if you'd like to add it. +- Для цього завдання не потрібні дужки або складні вирази. +- Числа і оператор розділені рівно одним пропуском. +- Не зайвим буде додати обробку помилок. diff --git a/1-js/05-data-types/05-array-methods/7-map-objects/solution.md b/1-js/05-data-types/05-array-methods/7-map-objects/solution.md index 2d8d4fb0e..9743cde8b 100644 --- a/1-js/05-data-types/05-array-methods/7-map-objects/solution.md +++ b/1-js/05-data-types/05-array-methods/7-map-objects/solution.md @@ -1,10 +1,10 @@ ```js run no-beautify -let john = { name: "John", surname: "Smith", id: 1 }; -let pete = { name: "Pete", surname: "Hunt", id: 2 }; -let mary = { name: "Mary", surname: "Key", id: 3 }; +let ivan = { name: "Іван", surname: "Іванко", id: 1 }; +let petro = { name: "Петро", surname: "Петренко", id: 2 }; +let mariya = { name: "Марія", surname: "Мрійко", id: 3 }; -let users = [ john, pete, mary ]; +let users = [ ivan, petro, mariya ]; *!* let usersMapped = users.map(user => ({ @@ -15,19 +15,19 @@ let usersMapped = users.map(user => ({ /* usersMapped = [ - { fullName: "John Smith", id: 1 }, - { fullName: "Pete Hunt", id: 2 }, - { fullName: "Mary Key", id: 3 } + { fullName: "Іван Іванко", id: 1 }, + { fullName: "Петро Петренко", id: 2 }, + { fullName: "Марія Мрійко", id: 3 } ] */ alert( usersMapped[0].id ); // 1 -alert( usersMapped[0].fullName ); // John Smith +alert( usersMapped[0].fullName ); // Іван Іванко ``` -Please note that in the arrow functions we need to use additional brackets. +Зверніть увагу, що для стрілкових функцій ми повинні використовувати додаткові дужки. -We can't write like this: +Ми не можемо написати ось так: ```js let usersMapped = users.map(user => *!*{*/!* fullName: `${user.name} ${user.surname}`, @@ -35,9 +35,9 @@ let usersMapped = users.map(user => *!*{*/!* }); ``` -As we remember, there are two arrow functions: without body `value => expr` and with body `value => {...}`. +Як ми памʼятаємо, є дві функції зі стрілками: без тіла `value => expr` та з тілом `value => {...}`. -Here JavaScript would treat `{` as the start of function body, not the start of the object. The workaround is to wrap them in the "normal" brackets: +Тут JavaScript трактуватиме `{` як початок тіла функції, а не початок обʼєкта. Щоб обійти це, потрібно укласти їх в круглі дужки: ```js let usersMapped = users.map(user => *!*({*/!* @@ -46,6 +46,6 @@ let usersMapped = users.map(user => *!*({*/!* })); ``` -Now fine. +Тепер усе добре. diff --git a/1-js/05-data-types/05-array-methods/7-map-objects/task.md b/1-js/05-data-types/05-array-methods/7-map-objects/task.md index b11d12155..e1dca6f61 100644 --- a/1-js/05-data-types/05-array-methods/7-map-objects/task.md +++ b/1-js/05-data-types/05-array-methods/7-map-objects/task.md @@ -2,35 +2,35 @@ importance: 5 --- -# Map to objects +# Трансформувати в обʼєкти -You have an array of `user` objects, each one has `name`, `surname` and `id`. +У вас є масив обʼєктів `user`, і у кожного з обʼєктів є `name`, `surname` та `id`. -Write the code to create another array from it, of objects with `id` and `fullName`, where `fullName` is generated from `name` and `surname`. +Напишіть код, який створить ще один масив обʼєктів з параметрами `id` й `fullName`, де `fullName` -- складається з `name` та `surname`. -For instance: +Наприклад: ```js no-beautify -let john = { name: "John", surname: "Smith", id: 1 }; -let pete = { name: "Pete", surname: "Hunt", id: 2 }; -let mary = { name: "Mary", surname: "Key", id: 3 }; +let ivan = { name: "Іван", surname: "Іванко", id: 1 }; +let petro = { name: "Петро", surname: "Петренко", id: 2 }; +let mariya = { name: "Марія", surname: "Мрійко", id: 3 }; -let users = [ john, pete, mary ]; +let users = [ ivan, petro, mariya ]; *!* -let usersMapped = /* ... your code ... */ +let usersMapped = /* ... ваш код ... */ */!* /* usersMapped = [ - { fullName: "John Smith", id: 1 }, - { fullName: "Pete Hunt", id: 2 }, - { fullName: "Mary Key", id: 3 } + { fullName: "Іван Іванко", id: 1 }, + { fullName: "Петро Петренко", id: 2 }, + { fullName: "Марія Мрійко", id: 3 } ] */ alert( usersMapped[0].id ) // 1 -alert( usersMapped[0].fullName ) // John Smith +alert( usersMapped[0].fullName ) // Іван Іванко ``` -So, actually you need to map one array of objects to another. Try using `=>` here. There's a small catch. \ No newline at end of file +Отже, насправді вам потрібно трансформувати один масив обʼєктів в інший. Спробуйте використовувати `=>`. Це невелика хитрість. \ No newline at end of file diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md index cfaf9761a..ce8dfb413 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md @@ -3,16 +3,16 @@ function sortByAge(arr) { arr.sort((a, b) => a.age - b.age); } -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let ivan = { name: "Іван", age: 25 }; +let petro = { name: "Петро", age: 30 }; +let mariya = { name: "Марія", age: 28 }; -let arr = [ pete, john, mary ]; +let arr = [ petro, ivan, mariya ]; sortByAge(arr); -// now sorted is: [john, mary, pete] -alert(arr[0].name); // John -alert(arr[1].name); // Mary -alert(arr[2].name); // Pete +// тепер відсортовано: [ivan, mariya, petro] +alert(arr[0].name); // Ivan +alert(arr[1].name); // Mariya +alert(arr[2].name); // Petro ``` diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md index 9a215c9f4..3740c45d9 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md @@ -2,23 +2,23 @@ importance: 5 --- -# Sort users by age +# Відсортувати користувачів за віком -Write the function `sortByAge(users)` that gets an array of objects with the `age` property and sorts them by `age`. +Напишіть функцію `sortByAge(users)`, яка приймає масив обʼєктів з властивістю `age` і сортує їх по ньому. -For instance: +Наприклад: ```js no-beautify -let john = { name: "John", age: 25 }; -let pete = { name: "Pete", age: 30 }; -let mary = { name: "Mary", age: 28 }; +let ivan = { name: "Іван", age: 25 }; +let petro = { name: "Петро", age: 30 }; +let mariya = { name: "Марія", age: 28 }; -let arr = [ pete, john, mary ]; +let arr = [ petro, ivan, mariya ]; sortByAge(arr); -// now: [john, mary, pete] -alert(arr[0].name); // John -alert(arr[1].name); // Mary -alert(arr[2].name); // Pete +// now: [ivan, mariya, petro] +alert(arr[0].name); // Іван +alert(arr[1].name); // Марія +alert(arr[2].name); // Петро ``` diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index 6674c444f..a17ba91cd 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md @@ -1,4 +1,4 @@ -The simple solution could be: +Простим рішенням може бути: ```js run *!* @@ -12,18 +12,18 @@ shuffle(arr); alert(arr); ``` -That somewhat works, because `Math.random() - 0.5` is a random number that may be positive or negative, so the sorting function reorders elements randomly. +Це, звичайно, буде працювати, тому що `Math.random() - 0.5` віддає випадкове число, яке може бути позитивним або негативним, отже, функція сортування змінює порядок елементів випадковим чином. -But because the sorting function is not meant to be used this way, not all permutations have the same probability. +Але оскільки метод `sort` не призначений для використання в таких випадках, не всі можливі варіанти мають однакову ймовірність. -For instance, consider the code below. It runs `shuffle` 1000000 times and counts appearances of all possible results: +Наприклад, розглянемо код нижче. Він запускає `shuffle` 1000000 раз та підраховує ймовірність появи для всіх можливих варіантів `arr`: ```js run function shuffle(array) { array.sort(() => Math.random() - 0.5); } -// counts of appearances for all possible permutations +// підрахунок імовірностей для всіх можливих варіантів let count = { '123': 0, '132': 0, @@ -39,13 +39,13 @@ for (let i = 0; i < 1000000; i++) { count[array.join('')]++; } -// show counts of all possible permutations +// показати кількість всіх можливих варіантів for (let key in count) { alert(`${key}: ${count[key]}`); } ``` -An example result (depends on JS engine): +Результат прикладу (залежать від ядра JS): ```js 123: 250706 @@ -56,30 +56,30 @@ An example result (depends on JS engine): 321: 125223 ``` -We can see the bias clearly: `123` and `213` appear much more often than others. +Тепер ми чітко бачимо відхилення: `123` й `213` зʼявляються набагато частіше, ніж інші варіанти. -The result of the code may vary between JavaScript engines, but we can already see that the approach is unreliable. +Результати цього коду можуть варіюватися при запуску на різних движках JavaScript, але очевидно, що такий підхід не надійний. -Why it doesn't work? Generally speaking, `sort` is a "black box": we throw an array and a comparison function into it and expect the array to be sorted. But due to the utter randomness of the comparison the black box goes mad, and how exactly it goes mad depends on the concrete implementation that differs between engines. +Так чому це не працює? Якщо говорити простими словами, то `sort` це "чорний ящик": ми кидаємо в нього масив і функцію порівняння, чекаючи отримати відсортований масив. Але через абсолютну хаотичності порівнянь чорний ящик божеволіє, і як саме він божеволіє, залежить від конкретної його реалізації, яка різна в різних двигунах JavaScript. -There are other good ways to do the task. For instance, there's a great algorithm called [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle). The idea is to walk the array in the reverse order and swap each element with a random one before it: +Є й інші хороші способи розвʼязувати цю задачу. Наприклад, є відмінний алгоритм під назвою [Тасування Фішера-Єйтса](https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle). Суть полягає в тому, щоб проходити по масиву у зворотному порядку і міняти місцями кожен елемент з випадковим елементом, який знаходиться перед ним. ```js function shuffle(array) { for (let i = array.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i + let j = Math.floor(Math.random() * (i + 1)); // випадковий індекс від 0 до i - // swap elements array[i] and array[j] - // we use "destructuring assignment" syntax to achieve that - // you'll find more details about that syntax in later chapters - // same can be written as: + // поміняти елементи місцями + // ми використовуємо для цього синтаксис "деструктивне присвоєння" + // докладніше про нього - в наступних розділах + // те ж саме можна записати як: // let t = array[i]; array[i] = array[j]; array[j] = t [array[i], array[j]] = [array[j], array[i]]; } } ``` -Let's test it the same way: +Давайте перевіримо цю реалізацію на тому ж прикладі: ```js run function shuffle(array) { @@ -89,7 +89,7 @@ function shuffle(array) { } } -// counts of appearances for all possible permutations +// підрахунок імовірності для всіх можливих варіантів let count = { '123': 0, '132': 0, @@ -105,13 +105,13 @@ for (let i = 0; i < 1000000; i++) { count[array.join('')]++; } -// show counts of all possible permutations +// показати кількість всіх можливих варіантів for (let key in count) { alert(`${key}: ${count[key]}`); } ``` -The example output: +Приклад виведення: ```js 123: 166693 @@ -122,6 +122,6 @@ The example output: 321: 166316 ``` -Looks good now: all permutations appear with the same probability. +Тепер все в порядку: всі варіанти зʼявляються з однаковою ймовірністю. -Also, performance-wise the Fisher-Yates algorithm is much better, there's no "sorting" overhead. +Крім того, якщо подивитися з точки зору продуктивності, то алгоритм "Тасування Фішера-Єйтса" набагато швидше, оскільки в ньому немає зайвих витрат на сортування. diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/task.md b/1-js/05-data-types/05-array-methods/9-shuffle/task.md index 970c53417..c8d5e4c45 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/task.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/task.md @@ -2,11 +2,11 @@ importance: 3 --- -# Shuffle an array +# Перемішайте масив -Write the function `shuffle(array)` that shuffles (randomly reorders) elements of the array. +Напишіть функцію `shuffle(array)`, яка перемішує (випадковим чином переставляє) елементи масиву. -Multiple runs of `shuffle` may lead to different orders of elements. For instance: +Багаторазові прогони через `shuffle` можуть привести до різних послідовностей елементів. Наприклад: ```js let arr = [1, 2, 3]; @@ -22,4 +22,4 @@ shuffle(arr); // ... ``` -All element orders should have an equal probability. For instance, `[1,2,3]` can be reordered as `[1,2,3]` or `[1,3,2]` or `[3,1,2]` etc, with equal probability of each case. +Все послідовності елементів повинні мати однакову ймовірність. Наприклад, `[1,2,3]` може бути перемішана як `[1,2,3]` або `[1,3,2]`, або `[3,1,2]` і т.д., з однаковою ймовірністю кожного випадку. diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md index b14e9a0be..9f76984d4 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -1,111 +1,111 @@ -# Array methods +# Методи масивів -Arrays provide a lot of methods. To make things easier, in this chapter they are split into groups. +Масиви пропонують безліч методів. Щоб було простіше, в цьому розділі вони розбиті на групи. -## Add/remove items +## Додавання/видалення елементів -We already know methods that add and remove items from the beginning or the end: +Ми вже знаємо методи, які додають чи видаляють елементи з початку чи з кінця: -- `arr.push(...items)` -- adds items to the end, -- `arr.pop()` -- extracts an item from the end, -- `arr.shift()` -- extracts an item from the beginning, -- `arr.unshift(...items)` -- adds items to the beginning. +- `arr.push(...items)` -- додає елементи до кінця, +- `arr.pop()` -- дістає елемент з кінця, +- `arr.shift()` -- дістає елемент з початку, +- `arr.unshift(...items)` -- додає елементи в початок. -Here are a few others. +Розглянемо й інші. ### splice -How to delete an element from the array? +Як видалити елемент з масиву? -The arrays are objects, so we can try to use `delete`: +Масиви є об’єктами, тому ми можемо спробувати використати `delete`: ```js run let arr = ["I", "go", "home"]; -delete arr[1]; // remove "go" +delete arr[1]; // видалимо "go" alert( arr[1] ); // undefined -// now arr = ["I", , "home"]; +// тепер arr = ["I", , "home"]; alert( arr.length ); // 3 ``` -The element was removed, but the array still has 3 elements, we can see that `arr.length == 3`. +Начебто, елемент був видалений, але при перевірці виявляється, що масив все ще має 3 елементи `arr.length == 3`. -That's natural, because `delete obj.key` removes a value by the `key`. It's all it does. Fine for objects. But for arrays we usually want the rest of elements to shift and occupy the freed place. We expect to have a shorter array now. +Це нормально, тому що все, що робить `delete obj.key` -- це видаляє значення за ключем `key`. Це нормально для обʼєктів, але для масивів ми звичайно хочемо, щоб інші елементи змістились і зайняли місце, що звільнилося. Ми чекаємо, що масив стане коротшим. -So, special methods should be used. +Тому слід застосовувати спеціальні методи. -The [arr.splice](mdn:js/Array/splice) method is a swiss army knife for arrays. It can do everything: insert, remove and replace elements. +Метод [arr.splice](mdn:js/Array/splice) -- це універсальний «швейцарський ніж» для роботи з масивами. Вміє все: додавати, видаляти і замінювати елементи. -The syntax is: +Його синтаксис: ```js arr.splice(start[, deleteCount, elem1, ..., elemN]) ``` -It modifies `arr` starting from the index `start`: removes `deleteCount` elements and then inserts `elem1, ..., elemN` at their place. Returns the array of removed elements. +Він змінює `arr` починаючи з позиції `start`: видаляє `deleteCount` елементів і вставляє `elem1, ..., elemN` на їх місце. Повертається масив з видалених елементів. -This method is easy to grasp by examples. +Цей метод легко зрозуміти на прикладах. -Let's start with the deletion: +Почнемо з видалення: ```js run let arr = ["I", "study", "JavaScript"]; *!* -arr.splice(1, 1); // from index 1 remove 1 element +arr.splice(1, 1); // з індексу 1 видалимо 1 елемент */!* alert( arr ); // ["I", "JavaScript"] ``` -Easy, right? Starting from the index `1` it removed `1` element. +Легко, правда? Починаючи з індексу `1`, він видалив `1` елемент. -In the next example we remove 3 elements and replace them with the other two: +У наступному прикладі ми видаляємо 3 елементи та замінюємо їх двома іншими: ```js run let arr = [*!*"I", "study", "JavaScript",*/!* "right", "now"]; -// remove 3 first elements and replace them with another +// видалимо 3 перших елементи і замінимо їх іншими arr.splice(0, 3, "Let's", "dance"); -alert( arr ) // now [*!*"Let's", "dance"*/!*, "right", "now"] +alert( arr ) // отримаєм [*!*"Let's", "dance"*/!*, "right", "now"] ``` -Here we can see that `splice` returns the array of removed elements: +Тут ми бачимо, що `splice` повертає масив видалених елементів: ```js run let arr = [*!*"I", "study",*/!* "JavaScript", "right", "now"]; -// remove 2 first elements +// видалимо 2 перших елементи let removed = arr.splice(0, 2); -alert( removed ); // "I", "study" <-- array of removed elements +alert( removed ); // "I", "study" <-- масив видалених елементів ``` -The `splice` method is also able to insert the elements without any removals. For that we need to set `deleteCount` to `0`: +Метод `splice` також може вставляти елементи без будь-яких видалень. Для цього нам потрібно встановити значення `0` для `deleteCount`: ```js run let arr = ["I", "study", "JavaScript"]; -// from index 2 -// delete 0 -// then insert "complex" and "language" +// починаючт з індекса 2 +// видалимо 0 елементів +// ваставити "complex" та "language" arr.splice(2, 0, "complex", "language"); alert( arr ); // "I", "study", "complex", "language", "JavaScript" ``` -````smart header="Negative indexes allowed" -Here and in other array methods, negative indexes are allowed. They specify the position from the end of the array, like here: +````smart header="Дозволяються відʼємні індекси" +Тут і в інших методах масиву допускаються відʼємні індекси. Вони дозволяють почати відлік елементів з кінця, як тут: ```js run let arr = [1, 2, 5]; -// from index -1 (one step from the end) -// delete 0 elements, -// then insert 3 and 4 +// починаючи з індексу -1 (перед останнім елементом) +// видалимо 0 елементів, +// вставимо значення 3 та 4 arr.splice(-1, 0, 3, 4); alert( arr ); // 1,2,3,4,5 @@ -114,62 +114,62 @@ alert( arr ); // 1,2,3,4,5 ### slice -The method [arr.slice](mdn:js/Array/slice) is much simpler than similar-looking `arr.splice`. +Метод [arr.slice](mdn:js/Array/slice) набагато простіший, ніж схожий на нього `arr.splice`. -The syntax is: +Його синтаксис: ```js arr.slice([start], [end]) ``` -It returns a new array copying to it all items from index `start` to `end` (not including `end`). Both `start` and `end` can be negative, in that case position from array end is assumed. +Він повертає новий масив, копіюючи до нього всі елементи від індексу `start` до `end` (не включаючи `end`). І `start`, і `end` можуть бути відʼємними. В такому випадку відлік буде здійснюватися з кінця масиву. -It's similar to a string method `str.slice`, but instead of substrings it makes subarrays. +Він подібний до рядкового методу `str.slice`, але замість підрядків створює підмасиви. -For instance: +Наприклад: ```js run let arr = ["t", "e", "s", "t"]; -alert( arr.slice(1, 3) ); // e,s (copy from 1 to 3) +alert( arr.slice(1, 3) ); // e,s (копіює з 1 до 3) -alert( arr.slice(-2) ); // s,t (copy from -2 till the end) +alert( arr.slice(-2) ); // s,t (копіює з -2 до кінця) ``` -We can also call it without arguments: `arr.slice()` creates a copy of `arr`. That's often used to obtain a copy for further transformations that should not affect the original array. +Можна викликати `slice` і взагалі без аргументів. `arr.slice()` створить копію масиву `arr`. Це часто використовують, щоб створити копію масиву для подальших перетворень, які не повинні змінювати вихідний масив. ### concat -The method [arr.concat](mdn:js/Array/concat) creates a new array that includes values from other arrays and additional items. +Метод [arr.concat](mdn:js/Array/concat) створює новий масив, в який копіює дані з інших масивів та додаткові значення. -The syntax is: +Його синтаксис: ```js arr.concat(arg1, arg2...) ``` -It accepts any number of arguments -- either arrays or values. +Він приймає будь-яку кількість аргументів -- масивів або значень. -The result is a new array containing items from `arr`, then `arg1`, `arg2` etc. +Результатом є новий масив, що містить елементи з `arr`, потім` arg1`, `arg2` тощо. -If an argument `argN` is an array, then all its elements are copied. Otherwise, the argument itself is copied. +Якщо аргумент `argN` є масивом, то всі його елементи копіюються. В іншому випадку буде скопійовано сам аргумент. -For instance: +Наприклад: ```js run let arr = [1, 2]; -// create an array from: arr and [3,4] +// створимо масив з: arr і [3,4] alert( arr.concat([3, 4]) ); // 1,2,3,4 -// create an array from: arr and [3,4] and [5,6] +// створимо масив з: arr, [3,4] і [5,6] alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 -// create an array from: arr and [3,4], then add values 5 and 6 +// створимо масив з: arr і [3,4], також добавимо значення 5 і 6 alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6 ``` -Normally, it only copies elements from arrays. Other objects, even if they look like arrays, are added as a whole: +Зазвичай він просто копіює елементи з масивів. Інші обʼєкти, навіть якщо вони виглядають як масиви, додаються як є: ```js run let arr = [1, 2]; @@ -182,7 +182,7 @@ let arrayLike = { alert( arr.concat(arrayLike) ); // 1,2,[object Object] ``` -...But if an array-like object has a special `Symbol.isConcatSpreadable` property, then it's treated as an array by `concat`: its elements are added instead: +... Але якщо обʼєкт має спеціальну властивість `Symbol.isConcatSpreadable`, то він обробляється `concat` як масив: замість нього додаються його числові властивості. Для коректної обробки в обʼєкті повинні бути числові властивості та length: ```js run let arr = [1, 2]; @@ -199,48 +199,48 @@ let arrayLike = { alert( arr.concat(arrayLike) ); // 1,2,something,else ``` -## Iterate: forEach +## Перебір: forEach -The [arr.forEach](mdn:js/Array/forEach) method allows to run a function for every element of the array. +Метод [arr.forEach](mdn:js/Array/forEach) дозволяє запускати функцію для кожного елемента масиву.. -The syntax: +Його синтаксис: ```js arr.forEach(function(item, index, array) { - // ... do something with item + // ... робимо щось з item }); ``` -For instance, this shows each element of the array: +Наприклад, цей код виведе на екран кожен елемент масиву: ```js run -// for each element call alert +// для кожного елементу викликається alert ["Bilbo", "Gandalf", "Nazgul"].forEach(alert); ``` -And this code is more elaborate about their positions in the target array: +А цей до того ж розповість і про свою позицію в масиві: ```js run ["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => { - alert(`${item} is at index ${index} in ${array}`); + alert(`${item} має позицію ${index} в масиві ${array}`); }); ``` -The result of the function (if it returns any) is thrown away and ignored. +Результат функції (якщо вона взагалі щось повертає) відкидається і ігнорується. -## Searching in array +## Пошук в масиві -Now let's cover methods that search in an array. +Далі розглянемо методи, які допоможуть знайти що-небудь в масиві. -### indexOf/lastIndexOf and includes +### indexOf/lastIndexOf та includes -The methods [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/lastIndexOf) and [arr.includes](mdn:js/Array/includes) have the same syntax and do essentially the same as their string counterparts, but operate on items instead of characters: +Методи [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/lastIndexOf) та [arr.includes](mdn:js/Array/includes) мають однаковий синтаксис і роблять по суті те ж саме, що і їх рядкові аналоги, але працюють з елементами замість символів: -- `arr.indexOf(item, from)` -- looks for `item` starting from index `from`, and returns the index where it was found, otherwise `-1`. -- `arr.lastIndexOf(item, from)` -- same, but looks for from right to left. -- `arr.includes(item, from)` -- looks for `item` starting from index `from`, returns `true` if found. +- `arr.indexOf(item, from)` -- шукає `item`, починаючи з індексу `from`, і повертає індекс, на якому був знайдений шуканий елемент, в іншому випадку -1. +- `arr.lastIndexOf(item, from)` -- те ж саме, але шукає справа наліво. +- `arr.includes(item, from)` -- шукає `item`, починаючи з індексу `from`, і повертає `true`, якщо пошук успішний. -For instance: +Наприклад: ```js run let arr = [1, 0, false]; @@ -252,41 +252,41 @@ alert( arr.indexOf(null) ); // -1 alert( arr.includes(1) ); // true ``` -Note that the methods use `===` comparison. So, if we look for `false`, it finds exactly `false` and not the zero. +Зверніть увагу, що методи використовують суворе порівняння `===`. Таким чином, якщо ми шукаємо `false`, він знаходить саме `false`, а не нуль. -If we want to check for inclusion, and don't want to know the exact index, then `arr.includes` is preferred. +Якщо ми хочемо перевірити наявність елемента, і нема потреби знати його точний індекс, тоді кращим є `arr.includes`. -Also, a very minor difference of `includes` is that it correctly handles `NaN`, unlike `indexOf/lastIndexOf`: +Крім того, дуже незначною відмінністю є те, що він правильно обробляє `NaN` на відміну від `indexOf/lastIndexOf`: ```js run const arr = [NaN]; -alert( arr.indexOf(NaN) ); // -1 (should be 0, but === equality doesn't work for NaN) -alert( arr.includes(NaN) );// true (correct) +alert( arr.indexOf(NaN) ); // -1 (повинен бути 0, але === перевірка на рівність не працює з NaN) +alert( arr.includes(NaN) );// true (вірно) ``` -### find and findIndex +### find і findIndex -Imagine we have an array of objects. How do we find an object with the specific condition? +Уявіть, що у нас є масив обʼєктів. Як нам знайти обʼєкт за певною умовою? -Here the [arr.find(fn)](mdn:js/Array/find) method comes in handy. +Тут стане в нагоді метод [arr.find(fn)](mdn:js/Array/find). -The syntax is: +Його синтаксис такий: ```js let result = arr.find(function(item, index, array) { - // if true is returned, item is returned and iteration is stopped - // for falsy scenario returns undefined + // якщо true - повертається поточний елемент і перебір закінчується + // якщо всі ітерації виявилися помилковими, повертається undefined }); ``` -The function is called for elements of the array, one after another: +Функція викликається по черзі для кожного елемента масиву: -- `item` is the element. -- `index` is its index. -- `array` is the array itself. +- `item` -- черговий елемент масиву. +- `index` -- його індекс. +- `array` -- сам масив. -If it returns `true`, the search is stopped, the `item` is returned. If nothing found, `undefined` is returned. +Якщо функція повертає `true`, пошук припиняється, повертається `item`. Якщо нічого не знайдено, повертається `undefined`. -For example, we have an array of users, each with the fields `id` and `name`. Let's find the one with `id == 1`: +Наприклад, у нас є масив користувачів, кожен з яких має поля `id` та `name`. Давайте знайдемо той де `id == 1`: ```js run let users = [ @@ -300,28 +300,28 @@ let user = users.find(item => item.id == 1); alert(user.name); // John ``` -In real life arrays of objects is a common thing, so the `find` method is very useful. +У реальному житті масиви обʼєктів -- звичайна справа, тому метод `find` вкрай корисний. -Note that in the example we provide to `find` the function `item => item.id == 1` with one argument. That's typical, other arguments of this function are rarely used. +Зверніть увагу, що в даному прикладі ми передаємо `find` функцію `item => item.id == 1`, з одним аргументом. Це типово, інші аргументи цієї функції використовуються рідко. -The [arr.findIndex](mdn:js/Array/findIndex) method is essentially the same, but it returns the index where the element was found instead of the element itself and `-1` is returned when nothing is found. +Метод [arr.findIndex](mdn:js/Array/findIndex) -- по суті, те ж саме, але повертає індекс, на якому був знайдений елемент, а не сам елемент, і `-1`, якщо нічого не знайдено. ### filter -The `find` method looks for a single (first) element that makes the function return `true`. +Метод `find` шукає один (перший) елемент, на якому функція-колбек поверне `true`. -If there may be many, we can use [arr.filter(fn)](mdn:js/Array/filter). +На той випадок, якщо знайдених елементів може бути багато, передбачений метод [arr.filter(fn)](mdn:js/Array/filter). -The syntax is similar to `find`, but `filter` returns an array of all matching elements: +Синтаксис цього методу схожий з `find`, але `filter` повертає масив з усіх відфільтрованих елементів: ```js let results = arr.filter(function(item, index, array) { - // if true item is pushed to results and the iteration continues - // returns empty array if nothing found + // якщо true - елемент додається до результату, і перебір триває + // повертається порожній масив в разі, якщо нічого не знайдено }); ``` -For instance: +Наприклад: ```js run let users = [ @@ -330,31 +330,31 @@ let users = [ {id: 3, name: "Mary"} ]; -// returns array of the first two users +// повертає масив перших двох користувачів let someUsers = users.filter(item => item.id < 3); alert(someUsers.length); // 2 ``` -## Transform an array +## Перетворення масиву -Let's move on to methods that transform and reorder an array. +Перейдемо до методів перетворення і впорядкування масиву. ### map -The [arr.map](mdn:js/Array/map) method is one of the most useful and often used. +Метод [arr.map](mdn:js/Array/map) є одним з найбільш корисних і часто використовуваних. -It calls the function for each element of the array and returns the array of results. +Він викликає функцію для кожного елемента масиву і повертає масив результатів виконання цієї функції. -The syntax is: +Синтаксис: ```js let result = arr.map(function(item, index, array) { - // returns the new value instead of item + // повертається нове значення замість елемента }); ``` -For instance, here we transform each element into its length: +Наприклад, тут ми перетворюємо кожен елемент на його довжину: ```js run let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length); @@ -363,41 +363,41 @@ alert(lengths); // 5,7,6 ### sort(fn) -The call to [arr.sort()](mdn:js/Array/sort) sorts the array *in place*, changing its element order. +Виклик [arr.sort()](mdn:js/Array/sort) сортує масив "на місці", змінюючи в ньому порядок елементів. -It also returns the sorted array, but the returned value is usually ignored, as `arr` itself is modified. +Він повертає відсортований масив, але зазвичай повертається значення ігнорується, так як змінюється сам `arr`. -For instance: +Наприклад: ```js run let arr = [ 1, 2, 15 ]; -// the method reorders the content of arr +// метод сортує вміст arr arr.sort(); alert( arr ); // *!*1, 15, 2*/!* ``` -Did you notice anything strange in the outcome? +Чи не помітили нічого дивного в цьому прикладі? -The order became `1, 15, 2`. Incorrect. But why? +Порядок став 1, 15, 2. Це неправильно! Але чому? -**The items are sorted as strings by default.** +**За замовчуванням елементи сортуються як рядки.** -Literally, all elements are converted to strings for comparisons. For strings, lexicographic ordering is applied and indeed `"2" > "15"`. +Буквально, елементи перетворюються в рядки при порівнянні. Для рядків застосовується лексикографічний порядок, і дійсно виходить, що `"2"> "15"`. -To use our own sorting order, we need to supply a function as the argument of `arr.sort()`. +Щоб використовувати наш власний порядок сортування, нам потрібно надати функцію як аргумент `arr.sort()`. -The function should compare two arbitrary values and return: +Функція повинна для пари значень повертати: ```js function compare(a, b) { - if (a > b) return 1; // if the first value is greater than the second - if (a == b) return 0; // if values are equal - if (a < b) return -1; // if the first value is less than the second + if (a > b) return 1; // якщо перше значення більше за друге + if (a == b) return 0; // якщо значення рівні + if (a < b) return -1; // якщо перше значення меньше за друге } ``` -For instance, to sort as numbers: +Наприклад, для сортування чисел: ```js run function compareNumeric(a, b) { @@ -415,13 +415,13 @@ arr.sort(compareNumeric); alert(arr); // *!*1, 2, 15*/!* ``` -Now it works as intended. +Тепер все працює як треба. -Let's step aside and think what's happening. The `arr` can be array of anything, right? It may contain numbers or strings or objects or whatever. We have a set of *some items*. To sort it, we need an *ordering function* that knows how to compare its elements. The default is a string order. +Візьмімо паузу і подумаємо, що ж відбувається. Згаданий раніше масив `arr` може бути масивом чого завгодно, вірно? Він може містити числа, рядки, обʼєкти або щось ще. У нас є набір якихось елементів. Щоб впорядкувати його, нам потрібна функція, яка визначає порядок, яка знає, як порівнювати його елементи. За замовчуванням елементи сортуються як рядки. -The `arr.sort(fn)` method implements a generic sorting algorithm. We don't need to care how it internally works (an optimized [quicksort](https://en.wikipedia.org/wiki/Quicksort) or [Timsort](https://en.wikipedia.org/wiki/Timsort) most of the time). It will walk the array, compare its elements using the provided function and reorder them, all we need is to provide the `fn` which does the comparison. +Метод `arr.sort(fn)` реалізує загальний алгоритм сортування. Нам не потрібно піклуватися про те, як він працює всередині (в більшості випадків це оптимізоване [швидке сортування](https://en.wikipedia.org/wiki/Quicksort) чи [Timsort](https://en.wikipedia.org/wiki/Timsort)). Реалізується прохід по масиву, порівнюються його елементи за допомогою наданої функції і змінюється їх порядок. Все, що залишається нам, це надати `fn`, яка робить це порівняння. -By the way, if we ever want to know which elements are compared -- nothing prevents from alerting them: +До речі, якщо ми коли-небудь захочемо дізнатися, які елементи порівнюються -- ніщо не заважає нам вивести їх на екран: ```js run [1, -2, 15, 2, 0, 8].sort(function(a, b) { @@ -430,12 +430,12 @@ By the way, if we ever want to know which elements are compared -- nothing preve }); ``` -The algorithm may compare an element with multiple others in the process, but it tries to make as few comparisons as possible. +В процесі роботи алгоритм може порівнювати елемент з іншими по кілька разів, але він намагається зробити якомога менше порівнянь. -````smart header="A comparison function may return any number" -Actually, a comparison function is only required to return a positive number to say "greater" and a negative number to say "less". +````smart header="Функція порівняння може повернути будь-яке число" +Насправді від функції порівняння потрібно будь-яке позитивне число, щоб сказати «більше», і негативне число, щоб сказати «менше». -That allows to write shorter functions: +Це дозволяє писати коротші функції: ```js run let arr = [ 1, 2, 15 ]; @@ -446,37 +446,37 @@ alert(arr); // *!*1, 2, 15*/!* ``` ```` -````smart header="Arrow functions for the best" -Remember [arrow functions](info:arrow-functions-basics)? We can use them here for neater sorting: +````smart header="Краще використовувати стрілочні функції" +Памʼятаєте [стрілкові функції](info:arrow-functions-basics)? Можна використовувати їх тут для того, щоб сортування виглядало більш акуратним: ```js arr.sort( (a, b) => a - b ); ``` -This works exactly the same as the longer version above. +Працюватиме точно так, як і довша версія вище. ```` -````smart header="Use `localeCompare` for strings" -Remember [strings](info:string#correct-comparisons) comparison algorithm? It compares letters by their codes by default. +````smart header="Використовуйте `localeCompare` для рядків" +Памʼятаєте алгоритм порівняння [рядків](info:string#correct-comparisons)? Він порівнює літери за їх кодами за замовчуванням. -For many alphabets, it's better to use `str.localeCompare` method to correctly sort letters, such as `Ö`. +Для багатьох алфавітів краще використовувати метод `str.localeCompare` для правильного сортування літер, як наприклад `Ö`. -For example, let's sort a few countries in German: +Наприклад, давайте відсортуємо кілька країн німецькою мовою: ```js run let countries = ['Österreich', 'Andorra', 'Vietnam']; -alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (wrong) +alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (не правильно) -alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (correct!) +alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (правильно!) ``` ```` ### reverse -The method [arr.reverse](mdn:js/Array/reverse) reverses the order of elements in `arr`. +Метод [arr.reverse](mdn:js/Array/reverse) змінює порядок елементів в `arr` на зворотний. -For instance: +Наприклад: ```js run let arr = [1, 2, 3, 4, 5]; @@ -485,36 +485,36 @@ arr.reverse(); alert( arr ); // 5,4,3,2,1 ``` -It also returns the array `arr` after the reversal. +Він також повертає масив `arr` зі зміненим порядком елементів. -### split and join +### split та join -Here's the situation from real life. We are writing a messaging app, and the person enters the comma-delimited list of receivers: `John, Pete, Mary`. But for us an array of names would be much more comfortable than a single string. How to get it? +Ситуація з реального життя. Ми пишемо додаток для обміну повідомленнями, і відвідувач вводить імена тих, кому його відправити, через кому: Вася, Петя, Маша. Але нам-то набагато зручніше працювати з масивом імен, ніж з одним рядком. Як його отримати? -The [str.split(delim)](mdn:js/String/split) method does exactly that. It splits the string into an array by the given delimiter `delim`. +Метод [str.split(delim)](mdn:js/String/split) саме це і робить. Він розбиває рядок на масив по заданому роздільнику `delim`. -In the example below, we split by a comma followed by space: +У прикладі нижче таким роздільником є ​​рядок з коми та пропуску. ```js run -let names = 'Bilbo, Gandalf, Nazgul'; +let names = 'Вася, Петя, Маша'; let arr = names.split(', '); for (let name of arr) { - alert( `A message to ${name}.` ); // A message to Bilbo (and other names) + alert( `A message to ${name}.` ); // Повідомлення отримають: Вася (і інші імена) } ``` -The `split` method has an optional second numeric argument -- a limit on the array length. If it is provided, then the extra elements are ignored. In practice it is rarely used though: +У методу split є необовʼязковий другий числовий аргумент -- обмеження на кількість елементів в масиві. Якщо їх більше, ніж вказано, то залишок масиву буде відкинутий. На практиці це рідко використовується: ```js run -let arr = 'Bilbo, Gandalf, Nazgul, Saruman'.split(', ', 2); +let arr = 'Вася, Петя, Маша, Іван'.split(', ', 2); -alert(arr); // Bilbo, Gandalf +alert(arr); // Вася, Петя ``` -````smart header="Split into letters" -The call to `split(s)` with an empty `s` would split the string into an array of letters: +````smart header="Розбивка на букви" +Виклик `split(s)` з порожнім аргументом `s` розбиває рядок на масив букв: ```js run let str = "test"; @@ -523,27 +523,27 @@ alert( str.split('') ); // t,e,s,t ``` ```` -The call [arr.join(glue)](mdn:js/Array/join) does the reverse to `split`. It creates a string of `arr` items joined by `glue` between them. +Виклик [arr.join(glue)](mdn:js/Array/join) робить в точності протилежне split. Він створює рядок з елементів `arr`, вставляючи `glue` між ними. -For instance: +Наприклад: ```js run -let arr = ['Bilbo', 'Gandalf', 'Nazgul']; +let arr = ["Вася", "Петя", "Маша"]; -let str = arr.join(';'); // glue the array into a string using ; +let str = arr.join(';'); // обʼєднуємо масив в рядок за допомогою ";" -alert( str ); // Bilbo;Gandalf;Nazgul +alert( str ); // Вася;Петя;Маша ``` ### reduce/reduceRight -When we need to iterate over an array -- we can use `forEach`, `for` or `for..of`. +Якщо нам потрібно перебрати масив -- ми можемо використовувати `forEach`, `for` або `for..of`. -When we need to iterate and return the data for each element -- we can use `map`. +Якщо нам потрібно перебрати масив і повернути дані для кожного елемента -- ми використовуємо `map`. -The methods [arr.reduce](mdn:js/Array/reduce) and [arr.reduceRight](mdn:js/Array/reduceRight) also belong to that breed, but are a little bit more intricate. They are used to calculate a single value based on the array. +Методи [arr.reduce](mdn:js/Array/reduce) та [arr.reduceRight](mdn:js/Array/reduceRight) схожі на методи вище, але вони трохи складніші. Вони використовуються для обчислення якогось одного значення на основі всього масиву. -The syntax is: +Синтаксис: ```js let value = arr.reduce(function(accumulator, item, index, array) { @@ -551,24 +551,24 @@ let value = arr.reduce(function(accumulator, item, index, array) { }, [initial]); ``` -The function is applied to all array elements one after another and "carries on" its result to the next call. +Функція застосовується по черзі до всіх елементів масиву і «переносить» свій результат на наступний виклик. -Arguments: +Аргументи: -- `accumulator` -- is the result of the previous function call, equals `initial` the first time (if `initial` is provided). -- `item` -- is the current array item. -- `index` -- is its position. -- `array` -- is the array. +- `accumulator` -- результат попереднього виклику цієї функції, дорівнює `initial` при першому виклику (якщо переданий `initial`), +- `item` -- черговий елемент масиву, +- `index` -- його індекс, +- `array` -- сам масив. -As function is applied, the result of the previous function call is passed to the next one as the first argument. +При виконанні функції результат її виклику на попередньому елементі масиву передається як перший аргумент. -So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end it becomes the result of `reduce`. +Зрозуміти простіше, якщо думати про перший аргумент як «збирач» результатів попередніх викликів функції. Після закінчення він стає результатом `reduce`. -Sounds complicated? +Звучить складно? -The easiest way to grasp that is by example. +Цей метод найпростіше зрозуміти на прикладі. -Here we get a sum of an array in one line: +Тут ми отримаємо суму всіх елементів масиву лише одним рядком: ```js run let arr = [1, 2, 3, 4, 5]; @@ -578,74 +578,74 @@ let result = arr.reduce((sum, current) => sum + current, 0); alert(result); // 15 ``` -The function passed to `reduce` uses only 2 arguments, that's typically enough. +Тут ми використовували найбільш поширений варіант `reduce`, який використовує тільки 2 аргументи. -Let's see the details of what's going on. +Давайте детальніше розберемо, як він працює. -1. On the first run, `sum` is the `initial` value (the last argument of `reduce`), equals `0`, and `current` is the first array element, equals `1`. So the function result is `1`. -2. On the second run, `sum = 1`, we add the second array element (`2`) to it and return. -3. On the 3rd run, `sum = 3` and we add one more element to it, and so on... +1. При першому запуску `sum` дорівнює `initial` (останній аргумент `reduce`), тобто `0`, а `current` -- перший елемент масиву, рівний `1`. Таким чином, результат функції дорівнює `1`. +2. При другому запуску `sum = 1`, і до нього ми додаємо другий елемент масиву (`2`). +3. При третьому запуску `sum = 3`, до якого ми додаємо наступний елемент, і так далі... -The calculation flow: +Потік обчислень виходить такий: ![](reduce.svg) -Or in the form of a table, where each row represents a function call on the next array element: +У вигляді таблиці, де кожен рядок -- виклик функції на черговому елементі масиву: -| |`sum`|`current`|result| +| |`sum`|`current`|результат| |---|-----|---------|---------| -|the first call|`0`|`1`|`1`| -|the second call|`1`|`2`|`3`| -|the third call|`3`|`3`|`6`| -|the fourth call|`6`|`4`|`10`| -|the fifth call|`10`|`5`|`15`| +|перший виклик|`0`|`1`|`1`| +|другий виклик|`1`|`2`|`3`| +|третій виклик|`3`|`3`|`6`| +|четвертий виклик|`6`|`4`|`10`| +|пʼятий виклик|`10`|`5`|`15`| -Here we can clearly see how the result of the previous call becomes the first argument of the next one. +Тут чітко видно, як результат попереднього виклику передається в перший аргумент наступного. -We also can omit the initial value: +Ми також можемо опустити початкове значення: ```js run let arr = [1, 2, 3, 4, 5]; -// removed initial value from reduce (no 0) +// прибрано початкове значення (немає 0 в кінці) let result = arr.reduce((sum, current) => sum + current); alert( result ); // 15 ``` -The result is the same. That's because if there's no initial, then `reduce` takes the first element of the array as the initial value and starts the iteration from the 2nd element. +Результат той самий. Це тому, що при відсутності `initial` в якості першого значення береться перший елемент масиву, а перебір стартує з другого. -The calculation table is the same as above, minus the first row. +Таблиця розрахунків така ж, як і вище, без першого рядка. -But such use requires an extreme care. If the array is empty, then `reduce` call without initial value gives an error. +Але таке використання вимагає крайньої обережності. Якщо масив порожній, то виклик `reduce` без початкового значення видасть помилку. -Here's an example: +Ось приклад: ```js run let arr = []; -// Error: Reduce of empty array with no initial value -// if the initial value existed, reduce would return it for the empty arr. +// Error: Reduce of empty array with no initial value +// якби існувало початкове значення, reduce повернув би його для порожнього масиву. arr.reduce((sum, current) => sum + current); ``` -So it's advised to always specify the initial value. +Тому рекомендується завжди вказувати початкове значення. -The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same, but goes from right to left. +Метод [arr.reduceRight](mdn:js/Array/reduceRight) працює аналогічно, але проходить по масиву справа наліво. ## Array.isArray -Arrays do not form a separate language type. They are based on objects. +Масиви не мають окремого типу в Javascript. Вони засновані на обʼєктах. -So `typeof` does not help to distinguish a plain object from an array: +Тому `typeof` не може відрізнити простий обʼєкт від масиву: ```js run -alert(typeof {}); // object -alert(typeof []); // same +alert(typeof {}); // обʼєкт +alert(typeof []); // також обʼєкт ``` -...But arrays are used so often that there's a special method for that: [Array.isArray(value)](mdn:js/Array/isArray). It returns `true` if the `value` is an array, and `false` otherwise. +...Але масиви використовуються настільки часто, що для цього придумали спеціальний метод: [Array.isArray(value)](mdn:js/Array/isArray). Він повертає `true`, якщо `value` -- це масив, інакше `false`. ```js run alert(Array.isArray({})); // false @@ -653,25 +653,25 @@ alert(Array.isArray({})); // false alert(Array.isArray([])); // true ``` -## Most methods support "thisArg" +## Більшість методів підтримують "thisArg" -Almost all array methods that call functions -- like `find`, `filter`, `map`, with a notable exception of `sort`, accept an optional additional parameter `thisArg`. +Майже всі методи масиву, які викликають функції -- такі як `find`, `filter`, `map`, за винятком методу `sort`, приймають необовʼязковий параметр `thisArg`. -That parameter is not explained in the sections above, because it's rarely used. But for completeness we have to cover it. +Цей параметр не пояснювався вище, оскільки дуже рідко використовується, але для кращого розуміння теми ми зобовʼязані його розглянути. -Here's the full syntax of these methods: +Ось повний синтаксис цих методів: ```js arr.find(func, thisArg); arr.filter(func, thisArg); arr.map(func, thisArg); // ... -// thisArg is the optional last argument +// thisArg - це необовʼязковий останній аргумент ``` -The value of `thisArg` parameter becomes `this` for `func`. +Значение параметра `thisArg` становится `this` для `func`. -For example, here we use a method of `army` object as a filter, and `thisArg` passes the context: +Наприклад, ось тут ми використовуємо метод обʼєкта `army` як фільтр, і `thisArg` передає йому контекст: ```js run let army = { @@ -690,7 +690,7 @@ let users = [ ]; *!* -// find users, for who army.canJoin returns true +// знайти користувачів, для яких army.canJoin повертає true let soldiers = users.filter(army.canJoin, army); */!* @@ -699,53 +699,53 @@ alert(soldiers[0].age); // 20 alert(soldiers[1].age); // 23 ``` -If in the example above we used `users.filter(army.canJoin)`, then `army.canJoin` would be called as a standalone function, with `this=undefined`, thus leading to an instant error. +Якби ми в прикладі вище використовували просто `users.filter(army.canJoin)`, то виклик `army.canJoin` був би в режимі окремої функції, з `this=undefined`. Це призвело б до помилки. -A call to `users.filter(army.canJoin, army)` can be replaced with `users.filter(user => army.canJoin(user))`, that does the same. The latter is used more often, as it's a bit easier to understand for most people. +Виклик `users.filter(army.canJoin, army)` можна замінити на `users.filter(user => army.canJoin(user))`, який робить те ж саме. Останній запис використовується навіть частіше, оскільки стрілочна функція більш наочна. -## Summary +## Підсумки -A cheat sheet of array methods: +Шпаргалка по методам масиву: -- To add/remove elements: - - `push(...items)` -- adds items to the end, - - `pop()` -- extracts an item from the end, - - `shift()` -- extracts an item from the beginning, - - `unshift(...items)` -- adds items to the beginning. - - `splice(pos, deleteCount, ...items)` -- at index `pos` deletes `deleteCount` elements and inserts `items`. - - `slice(start, end)` -- creates a new array, copies elements from index `start` till `end` (not inclusive) into it. - - `concat(...items)` -- returns a new array: copies all members of the current one and adds `items` to it. If any of `items` is an array, then its elements are taken. +- Для додавання/видалення елементів: + - `push(... items)` -- додає елементи до кінця, + - `arr.pop()` -- дістає елемент з кінця, + - `arr.shift()` -- дістає елемент з початку, + - `arr.unshift(...items)` -- додає елементи в початок. + - `splice(pos, deleteCount, ...items)` -- починаючи з індексу `pos`, видаляє `deleteCount` елементів та вставляє `items`. + - `slice(start, end)` -- створює новий масив, копіюючи в нього елементи з позиції `start` до `end` (не включаючи `end`). + - `concat(...items)` -- повертає новий масив: копіює всі члени поточного масиву і додає до нього `items`. Якщо якийсь із `items` є масивом, тоді беруться його елементи. -- To search among elements: - - `indexOf/lastIndexOf(item, pos)` -- look for `item` starting from position `pos`, return the index or `-1` if not found. - - `includes(value)` -- returns `true` if the array has `value`, otherwise `false`. - - `find/filter(func)` -- filter elements through the function, return first/all values that make it return `true`. - - `findIndex` is like `find`, but returns the index instead of a value. +- Для пошуку серед елементів: + - `indexOf/lastIndexOf(item, pos)` -- шукає `item`, починаючи з позиції `pos`, і повертає його індекс або `-1`, якщо нічого не знайдено. + - `includes(value)` -- повертає `true`, якщо в масиві є елемент `value`, в іншому випадку `false`. + - `find/filter(func)` -- фільтрує елементи через функцію і віддається перше/всі значення, при проходженні яких функція повертає `true`. + - `findIndex` схожий на `find`, але повертає індекс замість значення. -- To iterate over elements: - - `forEach(func)` -- calls `func` for every element, does not return anything. +- Для перебору елементів: + - `forEach(func)` -- викликає `func` для кожного елемента. Нічого не повертає. -- To transform the array: - - `map(func)` -- creates a new array from results of calling `func` for every element. - - `sort(func)` -- sorts the array in-place, then returns it. - - `reverse()` -- reverses the array in-place, then returns it. - - `split/join` -- convert a string to array and back. - - `reduce/reduceRight(func, initial)` -- calculate a single value over the array by calling `func` for each element and passing an intermediate result between the calls. +- Для перетворення масиву: + - `map(func)` -- створює новий масив з результатів виклику `func` для кожного елемента. + - `sort(func)` -- сортує масив «на місці», а потім повертає його. + - `reverse()` -- «на місці» змінює порядок елементів на протилежний і повертає змінений масив. + - `split/join` -- перетворює рядок в масив і назад. + - `reduce(func, initial)` -- обчислює одне значення на основі всього масиву, викликаючи `func` для кожного елемента і передаючи проміжний результат між викликами. -- Additionally: - - `Array.isArray(arr)` checks `arr` for being an array. +- Додатково: + - `Array.isArray(arr)` перевіряє, чи є `arr` масивом. -Please note that methods `sort`, `reverse` and `splice` modify the array itself. +Зверніть увагу, що методи `sort`, `reverse` та `splice` змінюють поточний масив. -These methods are the most used ones, they cover 99% of use cases. But there are few others: +Вивчених нами методів досить в 99% випадків, але існують і інші. -- [arr.some(fn)](mdn:js/Array/some)/[arr.every(fn)](mdn:js/Array/every) check the array. +- [arr.some(fn)](mdn:js/Array/some)/[arr.every(fn)](mdn:js/Array/every) перевіряють масив. - The function `fn` is called on each element of the array similar to `map`. If any/all results are `true`, returns `true`, otherwise `false`. +Функція `fn` викликається для кожного елемента масиву, подібного до `map`. Якщо будь-які/усі результати є `true`, повертає `true`, інакше `false`. - These methods behave sort of like `||` and `&&` operators: if `fn` returns a truthy value, `arr.some()` immediately returns `true` and stops iterating over the rest of items; if `fn` returns a falsy value, `arr.every()` immediately returns `false` and stops iterating over the rest of items as well. +Ці методи поводяться приблизно як оператори `||` та `&&`. Якщо `fn` повертає істинне значення, `arr.some()` негайно повертає `true` і припиняє ітерацію по решті елементів. Якщо `fn` повертає хибне значення, `arr.every()` негайно повертає `false` і припиняє ітерацію по решті елементів. - We can use `every` to compare arrays: +Ми можемо використовувати `every` для порівняння масивів: ```js run function arraysEqual(arr1, arr2) { return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]); @@ -754,16 +754,16 @@ These methods are the most used ones, they cover 99% of use cases. But there are alert( arraysEqual([1, 2], [1, 2])); // true ``` -- [arr.fill(value, start, end)](mdn:js/Array/fill) -- fills the array with repeating `value` from index `start` to `end`. +- [arr.fill(value, start, end)](mdn:js/Array/fill) -- заповнює масив повторюваними `value`, починаючи з індексу `start` до `end`. -- [arr.copyWithin(target, start, end)](mdn:js/Array/copyWithin) -- copies its elements from position `start` till position `end` into *itself*, at position `target` (overwrites existing). +- [arr.copyWithin(target, start, end)](mdn:js/Array/copyWithin) -- копіює свої елементи, починаючи з `start` і закінчуючи `end`, в власну позицію `target` (перезаписує існуючі). -- [arr.flat(depth)](mdn:js/Array/flat)/[arr.flatMap(fn)](mdn:js/Array/flatMap) create a new flat array from a multidimensional array. +- [arr.flat(depth)](mdn:js/Array/flat)/[arr.flatMap(fn)](mdn:js/Array/flatMap) -- створює новий, плоский масив з багатовимірного масиву. -For the full list, see the [manual](mdn:js/Array). +Повний список є в [довіднику MDN](mdn:js/Array). -From the first sight it may seem that there are so many methods, quite difficult to remember. But actually that's much easier. +На перший погляд, може здатися, що існує дуже багато різних методів, які досить складно запамʼятати. Але це тільки так здається. -Look through the cheat sheet just to be aware of them. Then solve the tasks of this chapter to practice, so that you have experience with array methods. +Уважно вивчіть шпаргалку, представлену вище, а потім, щоб попрактикуватися, вирішите завдання, запропоновані в цьому розділі. Так ви отримаєте необхідний досвід в правильному використанні методів масиву. -Afterwards whenever you need to do something with an array, and you don't know how -- come here, look at the cheat sheet and find the right method. Examples will help you to write it correctly. Soon you'll automatically remember the methods, without specific efforts from your side. +Кожного разу, коли вам буде необхідно щось зробити з масивом, а ви не знаєте, як це зробити -- приходьте сюди, дивіться на таблицю і шукайте правильний метод. Приклади допоможуть вам все зробити правильно, і незабаром ви швидко запамʼятайте методи без особливих зусиль. From cbda1c0cf682d80e7e0350d92cadef9080d0c3f8 Mon Sep 17 00:00:00 2001 From: Taras Date: Mon, 23 Aug 2021 21:55:07 +0300 Subject: [PATCH 12/27] Update 1-js/05-data-types/05-array-methods/1-camelcase/task.md --- 1-js/05-data-types/05-array-methods/1-camelcase/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/task.md b/1-js/05-data-types/05-array-methods/1-camelcase/task.md index adccc5392..69abda2d5 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/task.md +++ b/1-js/05-data-types/05-array-methods/1-camelcase/task.md @@ -6,7 +6,7 @@ importance: 5 Напишіть функцію `camelize(str)`, яка перетворює такі рядки "my-short-string" в "myShortString". -Тобто дефіси видаляються, а всі слова після них починаються з великою літери. +Тобто дефіси видаляються, а всі слова після них починаються з великої літери. Приклади: From 3f73a4be3d0872592ff216f1ff27a337dee9b314 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 21:58:47 +0300 Subject: [PATCH 13/27] Update 1-js/05-data-types/05-array-methods/10-average-age/task.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/10-average-age/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/10-average-age/task.md b/1-js/05-data-types/05-array-methods/10-average-age/task.md index caa601064..685c4e5f2 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/task.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/task.md @@ -4,7 +4,7 @@ importance: 4 # Вирахувати середній вік -Напишіть функцію `getAverageAge(users)`, яка приймає масив об’єктів з властивістю `age` та повертає середній вік. +Напишіть функцію `getAverageAge(users)`, яка приймає масив об’єктів з властивістю `age` та повертає середній вік. Формула обчислення середнього арифметичного значення: `(age1 + age2 + ... + ageN) / N`. From 007d5accb68df243df8f8541c01fa39d33e43e7e Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 21:59:00 +0300 Subject: [PATCH 14/27] Update 1-js/05-data-types/05-array-methods/11-array-unique/solution.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/11-array-unique/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md index c2da540c1..62c056190 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md +++ b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md @@ -28,7 +28,7 @@ alert( unique(strings) ); // Привіт, Світ, :-O Таким чином, якщо `result` містить `100` елементів і жоден з них не збігається з `str`, тоді він обійде весь `result` і зробить рівно `100` порівнянь. А якщо `result` великий масив, наприклад, `10000` елементів, то буде зроблено `10000` порівнянь. -Само по собі це не проблема, тому що JavaScript двигун дуже швидкий, тому обхід `10000` елементів масиву займає лічені мікросекунди. +Само собою це не проблема, адже рушій JavaScript дуже швидкий, тому обхід `10000` елементів масиву займає лічені мікросекунди. Але ми робимо таку перевірку для кожного елемента `arr` в циклі `for`. From 0a58cb5a72c9ae6f53845b3997909401d409990e Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 21:59:10 +0300 Subject: [PATCH 15/27] Update 1-js/05-data-types/05-array-methods/12-reduce-object/task.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/12-reduce-object/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md index a0b5cbe56..62af554e4 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md @@ -2,7 +2,7 @@ importance: 4 --- -# Створення об'єкта з ключем з масиву +# Створення об’єкта з ключем з масиву Припустимо, ми отримали масив користувачів у вигляді `{id:..., name:..., age:...}`. From 15efbc01ef5b1ea033d693e4e62905076410270d Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 21:59:44 +0300 Subject: [PATCH 16/27] Update 1-js/05-data-types/05-array-methods/9-shuffle/task.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/9-shuffle/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/task.md b/1-js/05-data-types/05-array-methods/9-shuffle/task.md index c8d5e4c45..abefef4e2 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/task.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/task.md @@ -22,4 +22,4 @@ shuffle(arr); // ... ``` -Все послідовності елементів повинні мати однакову ймовірність. Наприклад, `[1,2,3]` може бути перемішана як `[1,2,3]` або `[1,3,2]`, або `[3,1,2]` і т.д., з однаковою ймовірністю кожного випадку. +Всі послідовності елементів повинні мати однакову ймовірність. Наприклад, `[1,2,3]` може бути перемішана як `[1,2,3]` або `[1,3,2]`, або `[3,1,2]` тощо, з однаковою ймовірністю кожного випадку. From 77589754bdbbfac5a79c5d09e03b2eec06d26917 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 22:00:05 +0300 Subject: [PATCH 17/27] Update 1-js/05-data-types/05-array-methods/9-shuffle/solution.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/9-shuffle/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index a17ba91cd..23452f229 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md @@ -79,7 +79,7 @@ function shuffle(array) { } ``` -Давайте перевіримо цю реалізацію на тому ж прикладі: +Перевіримо цю реалізацію на тому ж прикладі: ```js run function shuffle(array) { From ca0c3b088bfb8fea82bc411706bde4ea3504b526 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 22:00:13 +0300 Subject: [PATCH 18/27] Update 1-js/05-data-types/05-array-methods/2-filter-range/task.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/2-filter-range/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/task.md b/1-js/05-data-types/05-array-methods/2-filter-range/task.md index d60c530d0..750074b83 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/task.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/task.md @@ -4,7 +4,7 @@ importance: 4 # Фільтрація за діапазоном -Напишіть функцію `filterRange(arr, a, b)`, яка приймає масив `arr`, шукає в ньому елементи більші-рівні `a` та менші-рівні `b` і віддає масив цих елементів. +Напишіть функцію `filterRange(arr, a, b)`, яка приймає масив `arr`, шукає в ньому елементи більші-рівні `a` та менші-рівні `b` і віддає масив цих елементів. Функція повинна повертати новий масив і не змінювати вихідний. From 86fccb400bc79929bda069a0a02bbacd68eb7cb4 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 22:00:20 +0300 Subject: [PATCH 19/27] Update 1-js/05-data-types/05-array-methods/2-filter-range/task.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/2-filter-range/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/task.md b/1-js/05-data-types/05-array-methods/2-filter-range/task.md index 750074b83..8b917eb86 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/task.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/task.md @@ -6,7 +6,7 @@ importance: 4 Напишіть функцію `filterRange(arr, a, b)`, яка приймає масив `arr`, шукає в ньому елементи більші-рівні `a` та менші-рівні `b` і віддає масив цих елементів. -Функція повинна повертати новий масив і не змінювати вихідний. +Функція повинна повертати новий масив і не змінювати вихідний. Наприклад: From 1ea72834ba8d456a107636d82062a462f5286f91 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 22:00:35 +0300 Subject: [PATCH 20/27] Update 1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md Co-authored-by: Taras --- .../05-array-methods/3-filter-range-in-place/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md index 5fdee1aaf..13798bfe2 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/task.md @@ -4,7 +4,7 @@ importance: 4 # Фільтрація за діапазоном "на місці" -Напишіть функцію `filterRangeInPlace(arr, a, b)`, яка приймає масив `arr` і видаляє з нього всі значення крім тих, які знаходяться між `a` і `b`. Тобто, перевірка має вигляд `a ≤ arr [i] ≤ b`. +Напишіть функцію `filterRangeInPlace(arr, a, b)`, яка приймає масив `arr` і видаляє з нього всі значення крім тих, які знаходяться між `a` і `b`. Тобто, перевірка має вигляд `a ≤ arr[i] ≤ b`. Функція повинна змінювати поточний масив і нічого не повертати. From 676d942379defd9be951a35b54c56dd5c3d98dcd Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 24 Aug 2021 22:01:10 +0300 Subject: [PATCH 21/27] Update 1-js/05-data-types/05-array-methods/7-map-objects/task.md Co-authored-by: Taras --- 1-js/05-data-types/05-array-methods/7-map-objects/task.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/7-map-objects/task.md b/1-js/05-data-types/05-array-methods/7-map-objects/task.md index e1dca6f61..d43614a82 100644 --- a/1-js/05-data-types/05-array-methods/7-map-objects/task.md +++ b/1-js/05-data-types/05-array-methods/7-map-objects/task.md @@ -4,7 +4,7 @@ importance: 5 # Трансформувати в обʼєкти -У вас є масив обʼєктів `user`, і у кожного з обʼєктів є `name`, `surname` та `id`. +У вас є масив обʼєктів `user`, і у кожного з обʼєктів є `name`, `surname` та `id`. Напишіть код, який створить ще один масив обʼєктів з параметрами `id` й `fullName`, де `fullName` -- складається з `name` та `surname`. From eff8fea761250089970b8f3dc6e3662a26583327 Mon Sep 17 00:00:00 2001 From: regnised Date: Tue, 24 Aug 2021 22:18:30 +0300 Subject: [PATCH 22/27] Add translate --- .../05-array-methods/12-reduce-object/task.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md index a0b5cbe56..47d57be5b 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md @@ -12,9 +12,9 @@ importance: 4 ```js let users = [ - {id: 'john', name: "John Smith", age: 20}, - {id: 'ann', name: "Ann Smith", age: 24}, - {id: 'pete', name: "Pete Peterson", age: 31}, + {id: 'іван', name: "Іван Іванко", age: 20}, + {id: 'ганна', name: "Ганна Іванко", age: 24}, + {id: 'петро', name: "Петро Петренко", age: 31}, ]; let usersById = groupById(users); @@ -23,9 +23,9 @@ let usersById = groupById(users); // після виклику функції ви повинні отримати: usersById = { - john: {id: 'john', name: "John Smith", age: 20}, - ann: {id: 'ann', name: "Ann Smith", age: 24}, - pete: {id: 'pete', name: "Pete Peterson", age: 31}, + іван: {id: 'іван', name: "Іван Іванко", age: 20}, + ганна: {id: 'ганна', name: "Ганна Іванко", age: 24}, + петро: {id: 'петро', name: "Петро Петренко", age: 31}, } */ ``` From c987f1d3ff968e04efed493f6d6cbce748e5b838 Mon Sep 17 00:00:00 2001 From: Taras Date: Wed, 25 Aug 2021 17:35:06 +0300 Subject: [PATCH 23/27] Update 1-js/05-data-types/05-array-methods/9-shuffle/solution.md --- 1-js/05-data-types/05-array-methods/9-shuffle/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index 23452f229..2084c2760 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md @@ -45,7 +45,7 @@ for (let key in count) { } ``` -Результат прикладу (залежать від ядра JS): +Результат прикладу (залежить від рушія JS): ```js 123: 250706 From b5a26f79817c818f5fde49b872b6ce8be080e34b Mon Sep 17 00:00:00 2001 From: Taras Date: Wed, 25 Aug 2021 17:35:24 +0300 Subject: [PATCH 24/27] Update 1-js/05-data-types/05-array-methods/9-shuffle/solution.md --- 1-js/05-data-types/05-array-methods/9-shuffle/solution.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index 2084c2760..1be050b83 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md @@ -124,4 +124,4 @@ for (let key in count) { Тепер все в порядку: всі варіанти зʼявляються з однаковою ймовірністю. -Крім того, якщо подивитися з точки зору продуктивності, то алгоритм "Тасування Фішера-Єйтса" набагато швидше, оскільки в ньому немає зайвих витрат на сортування. +Крім того, якщо подивитися з точки зору продуктивності, то алгоритм "Тасування Фішера-Єйтса" набагато швидший, оскільки в ньому немає зайвих витрат на сортування. From 3063331517d4815b467e4b1a09c52afa8dcb9bf2 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 7 Dec 2021 21:40:05 +0300 Subject: [PATCH 25/27] Promisification --- 1-js/11-async/06-promisify/article.md | 78 +++++++++++++-------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/1-js/11-async/06-promisify/article.md b/1-js/11-async/06-promisify/article.md index 1d81b31a6..d7b937398 100644 --- a/1-js/11-async/06-promisify/article.md +++ b/1-js/11-async/06-promisify/article.md @@ -1,12 +1,12 @@ -# Promisification +# Промісифікація -"Promisification" is a long word for a simple transformation. It's the conversion of a function that accepts a callback into a function that returns a promise. +"Промісифікація" -- це довге слово для простої трансформації. Це перетворення функції, яка приймає колбек та повертає проміс. -Such transformations are often required in real-life, as many functions and libraries are callback-based. But promises are more convenient, so it makes sense to promisify them. +Такі перетворення часто необхідні в реальному житті, оскільки багато функцій та бібліотеки засновані на колбеках, а використання промісів зручніше, тому є сенс «промісифікувати» їх. -For better understanding, let's see an example. +Для кращого розуміння розглянемо приклад. -For instance, we have `loadScript(src, callback)` from the chapter . +Ми візьмемо `loadScript(src, callback)` з розділу . ```js run function loadScript(src, callback) { @@ -14,24 +14,24 @@ function loadScript(src, callback) { script.src = src; script.onload = () => callback(null, script); - script.onerror = () => callback(new Error(`Script load error for ${src}`)); + script.onerror = () => callback(new Error(`Помилка завантаження скрипта ${src}`)); document.head.append(script); } -// usage: +// використання: // loadScript('path/script.js', (err, script) => {...}) ``` -The function loads a script with the given `src`, and then calls `callback(err)` in case of an error, or `callback(null, script)` in case of successful loading. That's a widespread agreement for using callbacks, we saw it before. +Функція завантажує скрипт використовуючи аргумент `src`, а потім викликає `callback(err)` у випадку помилки чи `callback(null, script)` у випадку успішного завантаження. Це усім відоме використання колбеку, яке ми вже бачили. -Let's promisify it. +Давайте промісифікуємо цю функцію. -We'll make a new function `loadScriptPromise(src)`, that does the same (loads the script), but returns a promise instead of using callbacks. +Створимо нову функцію `loadScriptPromise(src)`, яка робить те саме (завантажує скрипт), але повертає проміс замість використання колбеку. -In other words, we pass it only `src` (no `callback`) and get a promise in return, that resolves with `script` when the load is successful, and rejects with the error otherwise. +Іншими словами, ми будемо передавати тільки `src` (не `callback`) і отримаємо проміс у відповіді, який поверне `script` коли завантаження успішне, і помилку, якщо ні. -Here it is: +Реалізація такої функції: ```js let loadScriptPromise = function(src) { return new Promise((resolve, reject) => { @@ -42,23 +42,23 @@ let loadScriptPromise = function(src) { }); }; -// usage: +// використання: // loadScriptPromise('path/script.js').then(...) ``` -As we can see, the new function is a wrapper around the original `loadScript` function. It calls it providing its own callback that translates to promise `resolve/reject`. +Як ви можете бачити, нова функція -- це обгортка оригінальної `loadScript` функції. Вона викликає власний колбек, який працює з функціями проміса `resolve/reject`. -Now `loadScriptPromise` fits well in promise-based code. If we like promises more than callbacks (and soon we'll see more reasons for that), then we will use it instead. +Як бачимо, функція `loadScriptPromise` добре вписується в асинхронну поведінку промісів. -In practice we may need to promisify more than one function, so it makes sense to use a helper. +На практиці нам, швидше за все, знадобиться промісифікувати не одну функцію, тому є сенс зробити для цього спеціальну «функцію-помічник». -We'll call it `promisify(f)`: it accepts a to-promisify function `f` and returns a wrapper function. +Ми назвемо її `promisify(f)` -- вона приймає функцію для промісифікації `f` та повертає функцію-обгортку. ```js function promisify(f) { - return function (...args) { // return a wrapper-function (*) + return function (...args) { // повертає функію-обгортку (*) return new Promise((resolve, reject) => { - function callback(err, result) { // our custom callback for f (**) + function callback(err, result) { // наш спеціальний колбек для f (**) if (err) { reject(err); } else { @@ -66,41 +66,41 @@ function promisify(f) { } } - args.push(callback); // append our custom callback to the end of f arguments + args.push(callback); // додаємо колбек у кінець аргументів f - f.call(this, ...args); // call the original function + f.call(this, ...args); // викликаємо оригінальну функцію }); }; } -// usage: +// використання: let loadScriptPromise = promisify(loadScript); loadScriptPromise(...).then(...); ``` -The code may look a bit complex, but it's essentially the same that we wrote above, while promisifying `loadScript` function. +Код може виглядати дещо складним, але по суті він такий самий, як ми написали вище, промісифікуючи функцію `loadScript`. -A call to `promisify(f)` returns a wrapper around `f` `(*)`. That wrapper returns a promise and forwards the call to the original `f`, tracking the result in the custom callback `(**)`. +Виклик функції `promisify(f)` поверне функцію-обгортку для `f` `(*)`. Ця обгортка повертає проміс і викликає оригінальну функцію `f`, відстежуючи результат у спеціальному зворотному виклику `(**)`. -Here, `promisify` assumes that the original function expects a callback with exactly two arguments `(err, result)`. That's what we encounter most often. Then our custom callback is in exactly the right format, and `promisify` works great for such a case. +В цьому випадку, `promisify` припускає, що оригінальна функція очікує колбек тільки з двома аргументами `(err, result)`. З таким результатом колбеку ви працюватимете найчастіше. В такому випадку наш колбек написаний і відпрацьовуватиме правильно. -But what if the original `f` expects a callback with more arguments `callback(err, res1, res2, ...)`? +Але що, якщо вихідна функція `f` очікує колбек з більшою кількістю аргументів `callback(err, res1, res2, ...)`? -We can improve our helper. Let's make a more advanced version of `promisify`. +Ми можемо покращити нашу функцію-помічник. Зробімо розширену версію `promisify`. -- When called as `promisify(f)` it should work similar to the version above. -- When called as `promisify(f, true)`, it should return the promise that resolves with the array of callback results. That's exactly for callbacks with many arguments. +- Викличмо функцію `promisify(f)` з одним аргументом, то вона повинна працювати як і раніше. +- Викличмо функцію `promisify(f, true)` з двома аргументами, яка повинна повернути проміс, який поверне масив результатів з колбеку. Те ж саме повинно відбуватись для колбеку з багатьма аргументами. ```js -// promisify(f, true) to get array of results +// promisify(f, true) повинна повернути масив результатів function promisify(f, manyArgs = false) { return function (...args) { return new Promise((resolve, reject) => { - function *!*callback(err, ...results*/!*) { // our custom callback for f + function *!*callback(err, ...results*/!*) { // наш спеціальний колбек для f if (err) { reject(err); } else { - // resolve with all callback results if manyArgs is specified + // повернемо для всі результати колбека, якщо задано значення manyArgs === true *!*resolve(manyArgs ? results : results[0]);*/!* } } @@ -112,21 +112,21 @@ function promisify(f, manyArgs = false) { }; } -// usage: +// використання: f = promisify(f, true); f(...).then(arrayOfResults => ..., err => ...); ``` -As you can see it's essentially the same as above, but `resolve` is called with only one or all arguments depending on whether `manyArgs` is truthy. +Як ви можете бачити, це по суті те саме, що й вище, але `resolve` викликається лише з одним або з усіма аргументами залежно від того, чи є `manyArgs` істинним. -For more exotic callback formats, like those without `err` at all: `callback(result)`, we can promisify such functions manually without using the helper. +Для більш екзотичних форматів колбека, наприклад, без `err`: `callback(result)`, ми можемо промісифікувати функції без помічника, «вручну». -There are also modules with a bit more flexible promisification functions, e.g. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js, there's a built-in `util.promisify` function for that. +Існують також модулі з більш гнучкою промісифікацією, наприклад, [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify) або вбудована функція `util.promisify` в Node.js. ```smart -Promisification is a great approach, especially when you use `async/await` (see the next chapter), but not a total replacement for callbacks. +Промісифікація –- це чудовий підхід, особливо якщо ви будете використовувати `async/await` (дивіться наступний розділ), але вона не є повноцінно заміною будь-яких колбеків. -Remember, a promise may have only one result, but a callback may technically be called many times. +Пам'ятайте, проміс може мати лише один результат, але колбек технічно може викликатися скільки завгодно разів. -So promisification is only meant for functions that call the callback once. Further calls will be ignored. +Тому промісифікація використовується для функцій, що викликають колбек лише один раз. Наступні виклики колбека будуть проігноровані. ``` From 4684a0d636b4a550cb197ae6acd1ca7b82a340a1 Mon Sep 17 00:00:00 2001 From: Vasyl Onopriienko Date: Tue, 21 Dec 2021 00:39:05 +0300 Subject: [PATCH 26/27] Modules, introduction --- 1-js/13-modules/01-modules-intro/article.md | 324 ++++++++++---------- 1 file changed, 162 insertions(+), 162 deletions(-) diff --git a/1-js/13-modules/01-modules-intro/article.md b/1-js/13-modules/01-modules-intro/article.md index 6568c06f1..a3900732d 100644 --- a/1-js/13-modules/01-modules-intro/article.md +++ b/1-js/13-modules/01-modules-intro/article.md @@ -1,169 +1,169 @@ -# Modules, introduction +# Вступ до модулів -As our application grows bigger, we want to split it into multiple files, so called "modules". A module may contain a class or a library of functions for a specific purpose. +Оскільки наша програма з часом збільшується, ми захочемо розділити її на кілька файлів, так звані «модулі». Модуль може містити клас або бібліотеку функцій для певної мети. -For a long time, JavaScript existed without a language-level module syntax. That wasn't a problem, because initially scripts were small and simple, so there was no need. +Достатньо довгий час JavaScript існував без синтаксису модуля на мовному рівні. Це не було проблемою, тому що спочатку сценарії були невеликими й простими. -But eventually scripts became more and more complex, so the community invented a variety of ways to organize code into modules, special libraries to load modules on demand. +Але з часом скрипти ставали все складнішими, тому спільнота винайшла різноманітні способи організувати код у модулі. З’явилися бібліотеки для динамічного завантаження модулів. -To name some (for historical reasons): +Наприклад: -- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](http://requirejs.org/). -- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.js server. -- [UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS. +- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- одна з найстаріших модульних систем, спочатку реалізована бібліотекою [require.js](http://requirejs.org/). +- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- модульна система, створена для сервера Node.js. +- [UMD](https://github.com/umdjs/umd) -- ще одна модульна система, пропонується як універсальна, сумісна з AMD і CommonJS. -Now all these slowly become a part of history, but we still can find them in old scripts. +Тепер усі вони поступово стають частиною історії, хоча їх можна знайти в старих скриптах. -The language-level module system appeared in the standard in 2015, gradually evolved since then, and is now supported by all major browsers and in Node.js. So we'll study the modern JavaScript modules from now on. +Система модулів на рівні мови з’явилася у стандарті JavaScript у 2015 році та поступово еволюціонувала. На цей час вона підтримується більшістю браузерів та Node.js. Далі ми вивчатимемо саме її. -## What is a module? +## Що таке модуль? -A module is just a file. One script is one module. As simple as that. +Модуль -- це файл. Один скрипт -- це один модуль. -Modules can load each other and use special directives `export` and `import` to interchange functionality, call functions of one module from another one: +Модулі можуть завантажувати один одного та використовувати директиви `export` та `import`, щоб обмінюватися функціональністю, викликати функції одного модуля з іншого: -- `export` keyword labels variables and functions that should be accessible from outside the current module. -- `import` allows the import of functionality from other modules. +- `export` відзначає змінні та функції, які мають бути доступні поза поточним модулем. +- `import` дозволяє імпортувати функціональність з інших модулів. -For instance, if we have a file `sayHi.js` exporting a function: +Наприклад, якщо ми маємо файл `sayHi.js`, який експортує функцію: ```js // 📁 sayHi.js export function sayHi(user) { - alert(`Hello, ${user}!`); + alert(`Привіт, ${user}!`); } ``` -...Then another file may import and use it: +...Тоді інший файл може імпортувати її та використовувати: ```js // 📁 main.js import {sayHi} from './sayHi.js'; -alert(sayHi); // function... -sayHi('John'); // Hello, John! +alert(sayHi); // функція... +sayHi('Іван'); // Привіт, Іван! ``` -The `import` directive loads the module by path `./sayHi.js` relative to the current file, and assigns exported function `sayHi` to the corresponding variable. +Директива `import` завантажує модуль за шляхом `./sayHi.js` до поточного файлу та записує експортовану функцію `sayHi` у відповідну змінну. -Let's run the example in-browser. +Запустимо приклад у браузері. -As modules support special keywords and features, we must tell the browser that a script should be treated as a module, by using the attribute ` ``` -### Module-level scope +### Своя область видимості змінних -Each module has its own top-level scope. In other words, top-level variables and functions from a module are not seen in other scripts. +Кожен модуль має власну область видимості. Іншими словами, змінні та функції, оголошені в модулі, не доступні в інших скриптах. -In the example below, two scripts are imported, and `hello.js` tries to use `user` variable declared in `user.js`. It fails, because it's a separate module (you'll see the error in the console): +В прикладі нижче ми бачимо два імпортованих скрипта. Скрипт з файлу `hello.js` намагається використати змінну `user`, яка оголошена в `user.js`. В наступному коді ми отримаємо помилку: [codetabs src="scopes" height="140" current="index.html"] -Modules should `export` what they want to be accessible from outside and `import` what they need. +Модулі повинні "експортувати" те, що вони віддають на ззовні, і "імпортувати" те, що їм потрібно. -- `user.js` should export the `user` variable. -- `hello.js` should import it from `user.js` module. +- `user.js` повинен експортувати змінну `user`. +- `hello.js` повинен імпортувати змінну з `user.js` модуля. -In other words, with modules we use import/export instead of relying on global variables. +Іншими словами, використовуючи модулі ми користуємось import/export замість використання глобальних змінних. -This is the correct variant: +Правильний варіант: [codetabs src="scopes-working" height="140" current="hello.js"] -In the browser, if we talk about HTML pages, independent top-level scope also exists for each ` ``` ```smart -In the browser, we can make a variable window-level global by explicitly assigning it to a `window` property, e.g. `window.user = "John"`. +В браузері є можливість створити глобальну змінну рівня вікна браузера шляхом явного призначення її до об’єкту `window`, наприклад: `window.user = "Іван"`. -Then all scripts will see it, both with `type="module"` and without it. +Тоді всі скрипти типу `type="module"` і без нього будуть "бачити" змінну user. -That said, making such global variables is frowned upon. Please try to avoid them. +Тим не менш, створення таких глобальних змінних неприйнятно. Будь ласка, намагайтеся уникати їх. ``` -### A module code is evaluated only the first time when imported +### Код у модулі виконується лише один раз під час імпорту -If the same module is imported into multiple other modules, its code is executed only once, upon the first import. Then its exports are given to all further importers. +Якщо один і той же модуль використовується в декількох місцях, його код виконається тільки один раз, після чого експортована функціональність передається всім імпортерам. -The one-time evaluation has important consequences, that we should be aware of. +Розуміння одноразового обчислення і послідовності імпорту є важливою основою для розуміння роботи модулів. -Let's see a couple of examples. +Давайте подивимося приклади. -First, if executing a module code brings side-effects, like showing a message, then importing it multiple times will trigger it only once -- the first time: +По-перше, якщо при запуску модуля виникають побічні ефекти, наприклад, видається повідомлення, то імпорт модуля в декількох місцях покаже його тільки один раз -- при першому імпорті: ```js // 📁 alert.js -alert("Module is evaluated!"); +alert("Модуль виконаний!"); ``` ```js -// Import the same module from different files +// Імпорт одного і того ж модуля у різних файлах // 📁 1.js -import `./alert.js`; // Module is evaluated! +import `./alert.js`; // Модуль виконаний! // 📁 2.js -import `./alert.js`; // (shows nothing) +import `./alert.js`; // (нічого не покаже) ``` -The second import shows nothing, because the module has already been evaluated. +Другий імпорт нічого не покаже, тому що цей модуль вже був виконаний. -There's a rule: top-level module code should be used for initialization, creation of module-specific internal data structures. If we need to make something callable multiple times - we should export it as a function, like we did with `sayHi` above. +Існує правило: високорівневий код модуля повинен бути використаний для ініціалізації чи створення специфічних для модулів внутрішніх структур даних, а якщо ми хочемо, щоби щось можна було використовувати багато разів, то експортуємо це як функцію, подібну на ту, яку ми створили в `sayHi` вище. -Now, let's consider a deeper example. +Тепер більш ускладнений приклад. -Let's say, a module exports an object: +Уявімо, що модуль експортує об’єкт: ```js // 📁 admin.js export let admin = { - name: "John" + name: "Іван" }; ``` -If this module is imported from multiple files, the module is only evaluated the first time, `admin` object is created, and then passed to all further importers. +Якщо модуль імпортується в кількох файлах, код модуля буде виконано лише один раз, об’єкт `admin` буде створено і надалі буде переданий всім імпортерам. -All importers get exactly the one and only `admin` object: +Всі імпортери отримають один-єдиний об’єкт `admin`: ```js // 📁 1.js @@ -175,25 +175,25 @@ import {admin} from './admin.js'; alert(admin.name); // Pete *!* -// Both 1.js and 2.js reference the same admin object -// Changes made in 1.js are visible in 2.js +// Обидва файли, 1.js і 2.js, імпортують той самий об’єкт +// Зміни, зроблені в 1.js, з’являться в 2.js */!* ``` -As you can see, when `1.js` changes the `name` property in the imported `admin`, then `2.js` can see the new `admin.name`. +Як ви бачите, коли `1.js` змінює значення властивості `name` об’єкту `admin`, тоді інші модулі теж побачать ці зміни. -That's exactly because the module is executed only once. Exports are generated, and then they are shared between importers, so if something changes the `admin` object, other modules will see that. +Ще раз зауважимо -- модуль виконується лише один раз. Генерується експорт і після цього передається всім імпортерам, тому, якщо щось зміниться в об’єкті `admin`, то інші модулі теж побачать ці зміни. -**Such behavior is actually very convenient, because it allows us to *configure* modules.** +**Така поведінка дозволяє *конфігурувати* модулі під час першого імпорту. Ми можемо встановити його властивості один раз, і в подальших імпортах він буде налаштованим.** -In other words, a module can provide a generic functionality that needs a setup. E.g. authentication needs credentials. Then it can export a configuration object expecting the outer code to assign to it. +Іншими словами, модуль може забезпечити загальну функціональність, яка потребує налаштування. Наприклад для аутентифікації підготувати облікові дані. Потім він може експортувати об’єкт конфігурації, очікуючи, що зовнішній код буде посилатися на нього. -Here's the classical pattern: -1. A module exports some means of configuration, e.g. a configuration object. -2. On the first import we initialize it, write to its properties. The top-level application script may do that. -3. Further imports use the module. +Класичний шаблон використання: +1. Модуль експортує деякі значення конфігурації, наприклад, об’єкт конфігурації. +2. При першому імпорті ми його ініціалізуємо, записуємо в його властивості. Це може зробити скрипт програми верхнього рівня. +3. Подальші імпорти використовують цей модуль. -For instance, the `admin.js` module may provide certain functionality (e.g. authentication), but expect the credentials to come into the `config` object from outside: +Наприклад, модуль `admin.js` може забезпечувати певну функціональність (наприклад, аутентифікацію), але очікуймо, що облікові дані надходять в об’єкт `config` ззовні: ```js // 📁 admin.js @@ -204,9 +204,9 @@ export function sayHi() { } ``` -Here, `admin.js` exports the `config` object (initially empty, but may have default properties too). +В цьому прикладі, `admin.js` експортує `config` об’єкт (спочатку порожній, але також може мати властивості за замовчуванням). -Then in `init.js`, the first script of our app, we import `config` from it and set `config.user`: +Потім у `init.js`, першому скрипту нашої програми, ми імпортуємо `config` об’єкт і записуємо дані для ініціалізації `config.user`: ```js // 📁 init.js @@ -214,9 +214,9 @@ import {config} from './admin.js'; config.user = "Pete"; ``` -...Now the module `admin.js` is configured. +...Тепер модуль `admin.js` налаштовано. -Further importers can call it, and it correctly shows the current user: +Інші модулі можуть імпортувати його, і він правильно показує поточного користувача: ```js // 📁 another.js @@ -228,24 +228,24 @@ sayHi(); // Ready to serve, *!*Pete*/!*! ### import.meta -The object `import.meta` contains the information about the current module. +Об’єкт `import.meta` містить інформацію про поточний модуль. -Its content depends on the environment. In the browser, it contains the URL of the script, or a current webpage URL if inside HTML: +Вміст залежить від оточення. У браузері він містить посилання на скрипт або посилання на поточну вебсторінку, якщо модуль вбудований в HTML: ```html run height=0 ``` -### In a module, "this" is undefined +### У модулі «this» не визначено -That's kind of a minor feature, but for completeness we should mention it. +Це незначна особливість, але для повноти картини треба згадати про це. -In a module, top-level `this` is undefined. +У модулі на верхньому рівні `this` не визначено (undefined). -Compare it to non-module scripts, where `this` is a global object: +Порівняємо з не-модульними скриптами, там `this` -- глобальний об’єкт: ```html run height=0 ``` -## Browser-specific features +## Особливості у браузерах -There are also several browser-specific differences of scripts with `type="module"` compared to regular ones. +Є кілька інших, саме браузерних особливостей скриптів пов’язаних з `type="module"`. -You may want to skip this section for now if you're reading for the first time, or if you don't use JavaScript in a browser. +Якщо ви читаєте матеріал вперше або якщо не збираєтеся використовувати модулі в браузерах, то зараз можете пропустити цю секцію. -### Module scripts are deferred +### Модулі є відкладеними (deferred) -Module scripts are *always* deferred, same effect as `defer` attribute (described in the chapter [](info:script-async-defer)), for both external and inline scripts. +Модулі *завжди* виконуються у відкладеному (deferred) режимі, так само як скрипти з атрибутом `defer` (описаний у розділі [](info:script-async-defer)). Це вірно і для зовнішніх та вбудованих скриптів-модулів. -In other words: -- downloading external module scripts ` -Compare to regular script below: +Порівняйте зі звичайним скриптом нижче: ``` -Please note: the second script actually runs before the first! So we'll see `undefined` first, and then `object`. +Будь ласка, зверніть увагу: другий скрипт виконається раніше ніж перший! Тому ми побачимо спочатку `undefined`, а потім `object`. -That's because modules are deferred, so we wait for the document to be processed. The regular script runs immediately, so we see its output first. +Це тому, що модулі починають виконуватися після повного завантаження сторінки. Звичайні скрипти запускаються відразу, тому повідомлення зі звичайного скрипту ми бачимо першим. -When using modules, we should be aware that the HTML page shows up as it loads, and JavaScript modules run after that, so the user may see the page before the JavaScript application is ready. Some functionality may not work yet. We should put "loading indicators", or otherwise ensure that the visitor won't be confused by that. +При використанні модулів нам варто мати на увазі, що HTML-сторінка буде показана браузером до того, як виконаються модулі та JavaScript-програма буде готовий до роботи. Деякі функції можуть ще не працювати. Нам слід розмістити «індикатор завантаження» або ще щось, щоб не збентежити цим відвідувача. -### Async works on inline scripts +### Атрибут async працює у вбудованих скриптах -For non-module scripts, the `async` attribute only works on external scripts. Async scripts run immediately when ready, independently of other scripts or the HTML document. +Для немодульних скриптів атрибут `async` працює лише на зовнішніх скриптах. Скрипти з ним запускаються відразу по готовності, вони не чекають на інші скрипти або HTML-документ. -For module scripts, it works on inline scripts as well. +`Async` також працює у вбудованих сценаріях для модулів. -For example, the inline script below has `async`, so it doesn't wait for anything. +Наприклад, у скрипті нижче є `async`, тому він виконається одразу після завантаження, не чекаючи інших скриптів. -It performs the import (fetches `./analytics.js`) and runs when ready, even if the HTML document is not finished yet, or if other scripts are still pending. +Скрипт виконає імпорт (завантажить `./analytics.js`) і відразу запуститься, навіть, якщо HTML документ ще не завантажився чи якщо інші скрипти все ще завантажуються. -That's good for functionality that doesn't depend on anything, like counters, ads, document-level event listeners. +Це дуже корисно, коли модуль ні з чим не пов’язаний, наприклад, для лічильників, реклами, обробників подій. ```html - - + + ``` -### External scripts +### Зовнішні скрипти -External scripts that have `type="module"` are different in two aspects: +Зовнішні скрипти з атрибутом `type="module"` мають дві відмінності: -1. External scripts with the same `src` run only once: +1. Зовнішні скрипти з однаковим атрибутом `src` запускаються лише один раз: ```html - + ``` -2. External scripts that are fetched from another origin (e.g. another site) require [CORS](mdn:Web/HTTP/CORS) headers, as described in the chapter . In other words, if a module script is fetched from another origin, the remote server must supply a header `Access-Control-Allow-Origin` allowing the fetch. +2. Зовнішній скрипт, який завантажується з іншого домену (наприклад, іншого сайту), вимагає зазначення заголовків [CORS](mdn:Web/HTTP/CORS), як описано у главі . Іншими словами, якщо модульний скрипт завантажується з іншого домену, віддалений сервер повинен встановити заголовок `Access-Control-Allow-Origin`, що означає, що завантажити скрипт дозволено. ```html - - + + ``` - That ensures better security by default. + Це забезпечує кращу безпеку за промовчанням. -### No "bare" modules allowed +### Не допускаються «голі» модулі -In the browser, `import` must get either a relative or absolute URL. Modules without any path are called "bare" modules. Such modules are not allowed in `import`. +У браузері `import` має містити відносний або абсолютний шлях до модуля. Модулі без вказаного шляху до нього називаються «голими» (bare). Вони не дозволені в імпорті. -For instance, this `import` is invalid: +Наприклад, даний `import` неправильний: ```js -import {sayHi} from 'sayHi'; // Error, "bare" module -// the module must have a path, e.g. './sayHi.js' or wherever the module is +import {sayHi} from 'sayHi'; // Помилка, "голий" модуль +// імпорт модуля повинен мати шлях до нього, наприклад, './sayHi.js' чи 'C:/test/sayHi.js' (абсолютний шлях до модуля) ``` -Certain environments, like Node.js or bundle tools allow bare modules, without any path, as they have their own ways for finding modules and hooks to fine-tune them. But browsers do not support bare modules yet. +Інші оточення, наприклад Node.js, допускають використання «голих» модулів, без шляхів, тому що в них є свої правила, як працювати з такими модулями та де їх шукати. Але браузери поки не підтримують голі модулі. -### Compatibility, "nomodule" +### Сумісність, "nomodule" -Old browsers do not understand `type="module"`. Scripts of an unknown type are just ignored. For them, it's possible to provide a fallback using the `nomodule` attribute: +Старі браузери не розуміють атрибут `type="module"`. Скрипти з невідомим типом атрибутів просто ігноруються. Ми можемо зробити для них "резервний" скрипт за допомогою атрибуту `nomodule`: ```html run ``` -## Build tools +## Інструменти збирання -In real-life, browser modules are rarely used in their "raw" form. Usually, we bundle them together with a special tool such as [Webpack](https://webpack.js.org/) and deploy to the production server. +У реальному житті модулі в браузерах рідко використовуються у «сирому» вигляді. Зазвичай ми об’єднуємо модулі разом, використовуючи спеціальний інструмент, наприклад [Webpack](https://webpack.js.org/) і після викладаємо код на робочий сервер. -One of the benefits of using bundlers -- they give more control over how modules are resolved, allowing bare modules and much more, like CSS/HTML modules. +Одна з переваг використання збирача -- він надає більший контроль над тим, як модулі шукаються, дозволяє використовувати голі модулі та інші "власні" налаштування, наприклад CSS/HTML-модулі. -Build tools do the following: +Збирач робить таке: -1. Take a "main" module, the one intended to be put in ` ``` -That said, native modules are also usable. So we won't be using Webpack here: you can configure it later. +Хоча і «як є» модулі теж можна використовувати, а збирач налаштувати пізніше за необхідності. -## Summary +## Підсумки -To summarize, the core concepts are: +Підіб’ємо підсумки: -1. A module is a file. To make `import/export` work, browsers need `