├── .gitignore
├── README.md
├── git
├── git_cats.pdf
└── git_pheez.pdf
├── js
├── array.md
├── data_types.md
├── functions.md
├── if_else.md
├── loops.md
├── mutability_immutability.md
├── object.md
├── plan.md
├── scope.md
├── tdz_hoisting.md
├── type_conversion.md
├── type_methods.md
└── var_let_const.md
└── mobile_apps
├── BMI_Calc
├── .eslintrc.js
├── .gitignore
├── README.md
├── app.json
├── app
│ ├── _layout.tsx
│ ├── calculate-bmi.tsx
│ ├── index.tsx
│ └── result.tsx
├── assets
│ └── images
│ │ ├── adaptive-icon.png
│ │ ├── back-icon.svg
│ │ ├── favicon.png
│ │ ├── icon.png
│ │ ├── mainImg.png
│ │ ├── minus.svg
│ │ ├── plus.svg
│ │ ├── splash.png
│ │ └── textImg.png
├── babel.config.js
├── components
│ ├── base
│ │ ├── Button
│ │ │ └── Button.tsx
│ │ └── Switcher
│ │ │ └── Switcher.tsx
│ └── widgets
│ │ └── IncrementDecrementControl
│ │ └── IncrementDecrementControl.tsx
├── helpers
│ └── functions
│ │ ├── calculateBMI.tsx
│ │ └── resultToText.ts
├── package-lock.json
├── package.json
└── tsconfig.json
└── weather-app
├── .gitignore
├── README.md
├── api
└── url.ts
├── app.json
├── app
├── _layout.tsx
└── index.tsx
├── assets
└── images
│ ├── adaptive-icon.png
│ ├── favicon.png
│ ├── icon.png
│ └── splash.png
├── babel.config.js
├── components
└── SearchInput.tsx
├── eas.json
├── hooks
├── useCityWeather.ts
├── useCurrentPositionWeather.ts
└── useGetCities.ts
├── package-lock.json
├── package.json
├── tsconfig.json
└── types.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | *node_modules/
2 | *.expo/
3 | *dist/
4 | *npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | *.env
12 |
13 | # macOS
14 | *.DS_Store
15 |
16 |
17 |
18 | expo-env.d.ts
19 | # @end expo-cli
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 🌟 Курс мобильной разработки на React Native с TypeScript
2 |
3 | Добро пожаловать на наш курс по мобильной разработке! 🚀 Мы будем изучать основы создания мобильных приложений, используя **JavaScript**, **Git**, **TypeScript** и библиотеку **React Native**.
4 |
5 | ## 📚 Структура курса
6 |
7 | Курс состоит из нескольких модулей, каждый из которых охватывает ключевые темы разработки.
8 |
9 | ### 1. **Основы JavaScript** ✨
10 | В этом модуле мы познакомимся с JavaScript — языком программирования, лежащим в основе React и TypeScript. Рассмотрим:
11 | - **Основные типы данных и переменные** 🛠️
12 | - **Условия и циклы** 🔄
13 | - **Функции** 🔍
14 | - **Объекты и массивы** 📦
15 | - **Асинхронное программирование** (async/await) ⏳
16 |
17 | ### 2. **Основы Git** 🌐
18 | Знания Git необходимы для управления версионностью кода. Изучим:
19 | - **Основные команды Git:** `clone`, `commit`, `push`, `pull` 📥
20 | - **Ветвление и слияние изменений** 🔀
21 | - **Работа с GitHub и Pull Requests** 🗂️
22 |
23 | ### 3. **Введение в TypeScript** 🖥️
24 | TypeScript расширяет JavaScript типизацией, что позволяет избежать многих ошибок на ранних этапах разработки. Изучим:
25 | - **Отличие JavaScript от TypeScript** ⚖️
26 | - **Интерфейсы и типы** 📊
27 | - **Типизация** ✅
28 |
29 | ### 4. **React Native** 📱
30 | React Native позволяет создавать кроссплатформенные мобильные приложения. В этом модуле:
31 | - **Установка и настройка окружения** ⚙️
32 | - **Основы JSX и создание компонентов** 🏗️
33 | - **Хуки React** 🔗
34 | - **Работа со стилями и анимациями** 🎨
35 | - **Навигация между экранами** 🚪
36 | - **Работа с API и асинхронные операции** 🌐
37 |
38 | ---
--------------------------------------------------------------------------------
/git/git_cats.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/git/git_cats.pdf
--------------------------------------------------------------------------------
/git/git_pheez.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/git/git_pheez.pdf
--------------------------------------------------------------------------------
/js/array.md:
--------------------------------------------------------------------------------
1 | ## Что такое массив?
2 |
3 | - **Определение:** Массив — это список данных, который может хранить несколько значений в одной переменной.
4 |
5 | ## Почему массивы полезны?
6 |
7 | - Удобно хранить данные одной категории.
8 | - Легко работать с большими объемами данных.
9 |
10 | ## Синтаксис создания массива
11 |
12 | ```javascript
13 | const myArray = []; // Пустой массив
14 | const numbers = [1, 2, 3, 4, 5]; // Массив чисел
15 | const mixed = ["текст", 42, true]; // Смешанный массив тип any[]
16 | const strArr = ["one", "two", "three", "four", "five", "six"]; // Массив строк
17 | const fruitArray = ["apple", "orange", "banan"];
18 |
19 | const newArrayConstructor = new Array(4).fill(0) //[0,0,0,0]
20 | console.log(numbers); // [1, 2, 3, 4, 5]
21 | ```
22 |
23 | # Основные операции с массивами
24 |
25 | ## Доступ к элементам массива
26 |
27 | Индексы массива начинаются с 0.
28 |
29 | ```javascript
30 | const fruits = ["яблоко", "банан", "апельсин"];
31 | console.log(fruits[0]); // яблоко
32 | console.log(fruits[1]); // банан
33 | ```
34 |
35 | ## Изменение элементов массива
36 |
37 | Пример изменения значения:
38 |
39 | ```javascript
40 | const fruits = ["яблоко", "банан", "апельсин"];
41 | fruits[1] = "груша";
42 | console.log(fruits); // ['яблоко', 'груша', 'апельсин']
43 | ```
44 |
45 | ## Добавление и удаление элементов
46 |
47 | ### Добавление
48 |
49 | - С помощью `push()` (в конец массива):
50 |
51 | ```javascript
52 | const fruits = ["яблоко", "груша", "апельсин"];
53 | fruits.push('ананас');
54 | console.log(fruits); // ['яблоко', 'груша', 'апельсин', 'ананас']
55 | ```
56 |
57 | - С помощью `unshift()` (в начало массива):
58 |
59 | ```javascript
60 | const fruits = ["яблоко", "груша", "апельсин"];
61 | fruits.unshift('виноград');
62 | console.log(fruits); // ['виноград', 'яблоко', 'груша', 'апельсин']
63 | ```
64 |
65 | ### Удаление
66 |
67 | - С помощью `pop()` (удаляет последний элемент):
68 |
69 | ```javascript
70 | const fruits = ["виноград", "яблоко", "груша", "апельсин"];
71 | fruits.pop();
72 | console.log(fruits); // ['виноград', 'яблоко', 'груша']
73 | ```
74 |
75 | - С помощью `shift()` (удаляет первый элемент):
76 |
77 | ```javascript
78 | const fruits = ["виноград", "яблоко", "груша", "апельсин"];
79 | fruits.shift();
80 | console.log(fruits); // ['яблоко', 'груша', 'апельсин']
81 | ```
82 |
83 | ## Работа с длиной массива
84 |
85 | ### Свойство `.length`
86 |
87 | Определяет количество элементов в массиве:
88 |
89 | ```javascript
90 | const fruits = ['яблоко', 'груша', 'апельсин'];
91 | console.log(fruits.length); // 3
92 | ```
93 |
94 | ### Пример применения
95 |
96 | Добавление элемента в конец массива с использованием `.length`:
97 |
98 | ```javascript
99 | const fruits = ['яблоко', 'груша', 'апельсин'];
100 | fruits[fruits.length] = 'манго';
101 | console.log(fruits); // ['яблоко', 'груша', 'апельсин', 'манго']
102 | ```
103 | ## Метод `map()`
104 |
105 | Метод `map()` создает новый массив с результатом вызова указанной функции для каждого элемента массива.
106 |
107 | Пример:
108 |
109 | ```javascript
110 | const numbers = [1, 2, 3, 4];
111 | const doubled = numbers.map(function(number) {
112 | return number * 2;
113 | });
114 | const doubledShort = numbers.map(number => number * 2);
115 |
116 | console.log(doubled); // [2, 4, 6, 8]
117 | console.log(doubledShort); // [2, 4, 6, 8]
118 | ```
119 |
120 | ### Метод `forEach()`
121 |
122 | Метод `forEach()` применяет указанную функции для каждого элемента массива, но ничего не возвращает;
123 |
124 | Пример:
125 |
126 | ```javascript
127 | const fruits = ['яблоко', 'груша', 'апельсин'];
128 | fruits.forEach(function(fruit) {
129 | console.log(fruit);
130 | });
131 | ```
--------------------------------------------------------------------------------
/js/data_types.md:
--------------------------------------------------------------------------------
1 | # Типы данных в JavaScript
2 |
3 | ## Примитивные типы
4 |
5 | Примитивные типы данных в JavaScript включают:
6 |
7 | - `Number`
8 | - `BigInt`
9 | - `String`
10 | - `Symbol`
11 | - `Boolean`
12 | - `Undefined`
13 | - `Null`
14 |
15 | ### Общие характеристики примитивных типов
16 |
17 | - **Иммутабельность:** Примитивы неизменяемы. Например, если вы изменяете строку, создается новая строка, а не изменяется существующая.
18 | - **Сравнение по значению:** Примитивные значения сравниваются по значению, а не по ссылке.
19 | - **Автоматическое создание временных объектов:** Для доступа к методам строк и чисел JavaScript создает временные объектные обертки, которые уничтожаются сразу после использования.
20 | - **Хранят свои значения непосредственно:** Если вы присваиваете переменной значение примитивного типа, переменная содержит само значение.
21 | - **Типовые преобразования:** Примитивные типы могут быть автоматически преобразованы в другие типы, например, строка может быть преобразована в число при необходимости.
22 |
23 | ### Number
24 |
25 | - **Представление:** Числа с плавающей запятой двойной точности (64 бита, IEEE 754).
26 | - **Диапазон:** Примерно от `-1.7976931348623157 × 10^308` до `1.7976931348623157 × 10^308`.
27 | - **Проблемы:** Потери точности при работе с дробными числами, `0.1 + 0.2` не равно `0.3`.
28 | - **Специальные значения:** `Infinity`, `-Infinity`, `NaN`.
29 |
30 | ```javascript
31 | const one = 1;
32 | const exampleValue = 294834349;
33 | const minusValue = -9;
34 |
35 | console.log(one, exampleValue, minusValue);
36 |
37 | console.log(
38 | one + " is " + typeof one,
39 | "||",
40 | exampleValue + " is " + typeof exampleValue,
41 | "||",
42 | minusValue + " is " + typeof minusValue
43 | );
44 | ```
45 |
46 | ### NaN
47 |
48 | - **Значение:** Специальное значение, представляющее результат неудачных попыток преобразовать данные в число или операции, в которых результат не определен как число.
49 |
50 | ```javascript
51 | console.log(typeof NaN); // number
52 | console.log(0 / 0); // NaN
53 | console.log(Math.sqrt(-1)); // NaN
54 | ```
55 |
56 | ### Infinity
57 |
58 | - **Значение:** Математическая бесконечность. При делении числа на 0 (или на отрицательное число 0) получаем `Infinity` или `-Infinity`, соответственно.
59 |
60 | ```javascript
61 | console.log(typeof Infinity); // number
62 | console.log(Infinity); // Infinity
63 | console.log(1 / 0); // Infinity
64 | console.log(-Infinity); // -Infinity
65 | console.log(-1 / 0); // -Infinity
66 | ```
67 |
68 | ### String
69 |
70 | - **Представление:** UTF-16 последовательность символов, что означает, что каждый символ может занимать 16 бит.
71 | - **Шаблонные строки:** Позволяют использовать выражения внутри строки (интерполяция) и многострочные строки.
72 |
73 | ```javascript
74 | const imString = "example string";
75 | const imAnotherString = "я какая-то строчка";
76 | const imAnotherOneString = "а";
77 | const imStringWithTrue = "true";
78 | const imStringWithNumber = "234";
79 | const imStringWithChar = ".";
80 |
81 | const combinedStringWithTemplateLiterals = `${imString} | ${imAnotherString} | ${imAnotherOneString} | ${imStringWithTrue} | ${imStringWithNumber} | ${imStringWithChar}`;
82 |
83 | console.log(combinedStringWithTemplateLiterals);
84 | ```
85 |
86 | ### Boolean
87 |
88 | - **Представление:** Логические значения `true` и `false`.
89 | - **Использование:** Управление потоком выполнения (условные операторы, логические операции).
90 |
91 | ```javascript
92 | const exampleTrueBoolean = true;
93 | const exampleFalseBoolean = false;
94 | ```
95 |
96 | ### Undefined
97 |
98 | - **Представление:** Значение переменной, которая не была инициализирована.
99 | - **Использование:** По умолчанию возвращается для неинициализированных переменных, возвращается функциями без явного `return`.
100 |
101 | ```javascript
102 | let exampleUndefined;
103 | let anotherExampleUndefined = undefined;
104 | console.log(exampleUndefined); // undefined
105 | console.log(anotherExampleUndefined); // undefined
106 |
107 | ```
108 |
109 | ### Null
110 |
111 | - **Представление:** Намеренное отсутствие значения или объекта.
112 | - **Использование:** Явное указание на пустоту, инициализация переменных до присвоения реальных значений.
113 |
114 | ```javascript
115 | const exampleNull = null;
116 | ```
117 |
118 | ## Объектные типы
119 |
120 | Объектные типы данных в JavaScript включают:
121 |
122 | - `Object`
123 | - `Array`
124 | - `Function`
125 | - `Date`
126 | - `RegExp`
127 | - `Error`
128 |
129 | ### Общие характеристики объектных типов
130 |
131 | - **Мутабельность:** Объекты изменяемы. Вы можете изменять их свойства после создания.
132 | - **Сравнение по ссылке:** Объектные значения сравниваются по ссылке, а не по значению.
133 | - **Хранят ссылки на значения:** Переменные, содержащие объектные типы, хранят ссылки на объекты, а не сами значения.
134 | - **Методы и свойства:** Объекты могут иметь методы и свойства, которые могут быть вызваны и изменены.
135 |
136 | ## Копирование по ссылке
137 |
138 | Мутабельные объекты копируются по ссылке. Это означает, что если вы измените копию объекта, оригинальный объект также изменится.
139 |
140 | ```javascript
141 | const originalArray = [1, 2, 3];
142 | const copiedArray = originalArray;
143 |
144 | copiedArray[0] = 10;
145 | console.log(originalArray); // [10, 2, 3]
146 | console.log(copiedArray); // [10, 2, 3]
147 | ```
148 |
--------------------------------------------------------------------------------
/js/functions.md:
--------------------------------------------------------------------------------
1 | # Функции в JavaScript
2 |
3 | Функции в JavaScript — это блоки кода, которые можно переиспользовать. Они позволяют выполнять определённые задачи или вычисления и упрощают структуру кода.
4 |
5 | ## Что такое функции?
6 |
7 | - **Определение:** Функция — это именованный блок кода, который можно вызывать (вызывать — это значит выполнять) в любой части программы.
8 | - **Аргументы:** Функции могут принимать данные, называемые аргументами, которые могут влиять на их поведение.
9 | - **Возврат значения:** Функции могут возвращать значения, которые можно использовать в других частях кода.
10 |
11 | ## Зачем нужны функции?
12 |
13 | - **Упрощение кода:** Позволяют разбивать программу на более мелкие части, делая её проще для понимания.
14 | - **Повторное использование:** Один и тот же код можно вызывать несколько раз, что уменьшает количество дублирующегося кода.
15 | - **Организация:** Помогают структурировать программу логически.
16 |
17 | ## Как пользоваться функциями?
18 |
19 | ### Объявление функции
20 |
21 | ```javascript
22 | function имяФункции(аргументы) {
23 | return значение;
24 | }
25 | //Function Declaration
26 | function greet(name) {
27 | return `Hello, ${name}!`;
28 | }
29 |
30 | //Function Expression
31 | const add = function(a, b) {
32 | return a + b;
33 | };
34 |
35 | // Arrow Function
36 | const multiply = (a, b) => a * b;
37 |
38 |
39 | const exampleGreet = greet("Kaliningrad"); // результат будет равен `Hello, Kaliningrad`
40 | const exampleAdd = add(5,10); // результат будет равен 15
41 | const exampleMultiply = multiply(5,10); // результат будет равен 50
42 |
43 | ```
44 |
45 | ## Способы объявления функции
46 |
47 | - **Function Declaration (Объявление функции)**
48 | - **Function Expression (Функциональное выражение)**
49 | - **Arrow Function (Стрелочная функция)**
50 | - **Immediately Invoked Function Expression (IIFE)**
51 |
52 | ### Function Declaration
53 |
54 | - **Поддержка Hoisting:** Функции, объявленные таким способом, поднимаются (hoisted) в начало своей области видимости. Это означает, что вы можете вызывать функцию до её объявления в коде.
55 | - **Создание именованной функции:** Имя функции используется для вызова и для ссылок в коде.
56 | - **Можно использовать до объявления в коде.**
57 |
58 | ```javascript
59 | console.log(myFunction(2, 3)); // 5
60 |
61 | function myFunction(a, b) {
62 | return a + b;
63 | }
64 | ```
65 |
66 | ### Arrow Function
67 |
68 | Стрелочные функции — это более короткий синтаксис для определения функций. Они имеют ряд особенностей, таких как отсутствие своего `this`, `arguments`, `super` и `new.target`. Обычно они используются для написания простых функций.
69 |
70 | - **Не поддерживает Hoisting**
71 |
72 | ```javascript
73 | const myFunction = (a, b) => a + b;
74 |
75 | console.log(myFunction(2, 3)); // 5
76 |
77 | const myAnotherFunction = (a, b) => {
78 | return a + b;
79 | };
80 |
81 | console.log(myAnotherFunction(5, 10)); // 15
82 | ```
83 |
--------------------------------------------------------------------------------
/js/if_else.md:
--------------------------------------------------------------------------------
1 | # Условные операторы в JavaScript
2 |
3 | ## `if`
4 |
5 | Используется для выполнения кода, если условие истинно.
6 |
7 | ### Пример использования `if`:
8 |
9 | ```javascript
10 | if (условие) {
11 | // Код, который выполнится, если условие истинно
12 | }
13 | ```
14 |
15 | ## `if...else`
16 |
17 | Используется для выполнения одного блока кода, если условие истинно, и другого блока кода, если условие ложно.
18 |
19 | ### Пример использования `if...else`:
20 |
21 | ```javascript
22 | if (условие) {
23 | // Код, который выполнится, если условие истинно
24 | } else {
25 | // Код, который выполнится, если условие ложно
26 | }
27 | ```
28 |
29 | ## `if...else if...else`
30 |
31 | Используется для проверки нескольких условий. Выполняет соответствующий блок кода для первого истинного условия.
32 |
33 | ### Пример использования `if...else if...else`:
34 |
35 | ```javascript
36 | if (условие1) {
37 | // Код для первого условия
38 | } else if (условие2) {
39 | // Код для второго условия
40 | } else {
41 | // Код, который выполнится, если ни одно из условий не истинно
42 | }
43 | ```
44 |
45 | ## Тернарный оператор `?`
46 |
47 | Используется для краткой записи условного оператора `if...else`.
48 |
49 | ### Пример использования тернарного оператора:
50 |
51 | ```javascript
52 | условие ? выражение1 : выражение2;
53 | ```
54 |
55 | ## `switch`
56 |
57 | Используется для выполнения одного из нескольких блоков кода в зависимости от значения выражения.
58 |
59 | ### Пример использования `switch`:
60 |
61 | ```javascript
62 | switch (выражение) {
63 | case значение1:
64 | // Код для значения1
65 | break;
66 | case значение2:
67 | // Код для значения2
68 | break;
69 | default:
70 | // Код, который выполнится, если ни одно значение не совпало
71 | }
72 | ```
--------------------------------------------------------------------------------
/js/loops.md:
--------------------------------------------------------------------------------
1 | ## 1. for (обычный цикл)
2 |
3 | Используется для выполнения кода определённое количество раз.
4 |
5 | ```javascript
6 | for (let i = 0; i < 5; i++) {
7 | console.log("Итерация:", i);
8 | }
9 | ```
10 |
11 | ## 2. for...in (цикл по ключам объекта)
12 |
13 | Используется для перебора ключей объекта.
14 |
15 | ```javascript
16 | const obj = {a: 1, b: 2, c: 3};
17 |
18 | for (let key in obj) {
19 | console.log("Ключ:", key, "Значение:", obj[key]);
20 | }
21 | ```
22 |
23 | ## 3. for...of (цикл по значениям массива)
24 |
25 | Используется для перебора значений массива.
26 |
27 | ```javascript
28 | const arr = [10, 20, 30];
29 |
30 | for (let value of arr) {
31 | console.log("Значение:", value);
32 | }
33 | ```
34 |
35 | ## 4. while (цикл с предусловием)
36 |
37 | Используется, когда количество итераций заранее неизвестно, и нужно повторять выполнение кода, пока выполняется условие.
38 |
39 | ```javascript
40 | let i = 0;
41 | while (i < 5) {
42 | console.log("Итерация:", i);
43 | i++;
44 | }
45 | ```
46 |
47 | ## 5. do...while (цикл с постусловием)
48 |
49 | Гарантированно выполнится минимум один раз, так как проверка условия происходит после выполнения тела цикла.
50 |
51 | ```javascript
52 | let j = 0;
53 | do {
54 | console.log("Итерация:", j);
55 | j++;
56 | } while (j < 5);
57 | ```
58 |
59 | ## 6. break (прерывание цикла)
60 |
61 | Полностью останавливает выполнение цикла.
62 |
63 | ```javascript
64 | for (let i = 0; i < 10; i++) {
65 | if (i === 5) {
66 | break; // Выход из цикла при i === 5
67 | }
68 | console.log("Итерация:", i);
69 | }
70 | ```
71 |
72 | ## 7. continue (пропуск итерации)
73 |
74 | Пропускает текущую итерацию и переходит к следующей.
75 |
76 | ```javascript
77 | for (let i = 0; i < 10; i++) {
78 | if (i % 2 === 0) {
79 | continue; // Пропускает четные числа
80 | }
81 | console.log("Итерация:", i);
82 | }
83 | ```
84 |
--------------------------------------------------------------------------------
/js/mutability_immutability.md:
--------------------------------------------------------------------------------
1 | # Мутабельность и иммутабельность в JavaScript
2 |
3 | ## Мутабельность
4 |
5 | Мутабельные объекты могут изменяться после их создания. Это означает, что вы можете изменять их свойства или содержимое.
6 |
7 | ### Примеры мутабельных объектов
8 |
9 | 1. **Объекты (Object)**
10 | 2. **Массивы (Array)**
11 |
12 | ### Пример мутабельного объекта:
13 | ```javascript
14 | const person = {
15 | name: "John",
16 | age: 30
17 | };
18 |
19 | // Изменение свойства объекта
20 | person.age = 31;
21 | console.log(person.age); // 31
22 | ```
23 |
24 | ### Пример мутабельного массива:
25 | ```javascript
26 | const numbers = [1, 2, 3];
27 |
28 | // Изменение элемента массива
29 | numbers[0] = 10;
30 | console.log(numbers); // [10, 2, 3]
31 | ```
32 |
33 | ## Иммутабельность
34 |
35 | Иммутабельные объекты не могут изменяться после их создания. Любые изменения приводят к созданию нового объекта.
36 |
37 | ### Примеры иммутабельных объектов
38 |
39 | 1. **Примитивные типы (например, строки, числа)**
40 |
41 | ### Пример иммутабельной строки:
42 | ```javascript
43 | let greeting = "Hello";
44 | let newGreeting = greeting.replace("Hello", "Hi");
45 |
46 | console.log(greeting); // "Hello"
47 | console.log(newGreeting); // "Hi"
48 | ```
49 |
50 | ### Пример иммутабельного числа:
51 | ```javascript
52 | let number = 10;
53 | let newNumber = number + 5;
54 |
55 | console.log(number); // 10
56 | console.log(newNumber); // 15
57 | ```
58 |
59 | ## Итог
60 |
61 | | Характеристика | Мутабельные объекты | Иммутабельные объекты |
62 | |----------------------|------------------------------|-----------------------------|
63 | | Изменяемость | Да | Нет |
64 | | Сравнение | По ссылке | По значению |
65 | | Примеры | Объекты, массивы | Строки, числа |
66 |
--------------------------------------------------------------------------------
/js/object.md:
--------------------------------------------------------------------------------
1 | # Что такое объекты в JavaScript?
2 |
3 | Объекты — это структура данных, которая позволяет хранить связанные данные и функции (методы) в одном месте. По сути, это контейнер, который помогает организовать информацию, связывая ключи (имена) с их значениями.
4 |
5 | Представь, что объект — это коробка с наклейками (ключами), к которым прикреплены вещи (значения). Например, коробка с информацией о человеке:
6 |
7 | ```javascript
8 | const person = {
9 | name: "Иван", // Ключ "name", значение "Иван"
10 | age: 25, // Ключ "age", значение 25
11 | isStudent: true, // Ключ "isStudent", значение true
12 | };
13 |
14 | console.log(person.name); // Иван
15 | ```
16 |
17 | ## Для чего нужны объекты?
18 |
19 | Объекты нужны, чтобы:
20 |
21 | - **Организовывать данные.** Они помогают группировать информацию, относящуюся к одному элементу (например, данные о пользователе, автомобиле или товаре в интернет-магазине).
22 | - **Работать с более сложными структурами данных.** Например, объект может содержать другие объекты или массивы.
23 | - **Хранить данные о свойствах и действиях.** Объекты могут содержать функции, которые описывают поведение (например, что человек может сказать "Привет").
24 |
25 | ## Как взаимодействовать с объектами?
26 |
27 | ### Создание объекта
28 |
29 | Есть несколько способов создать объект:
30 |
31 | #### Литерал объекта
32 |
33 | ```javascript
34 | const car = {
35 | brand: "Toyota",
36 | model: "Camry",
37 | year: 2020,
38 | };
39 | ```
40 |
41 | #### Через конструктор
42 |
43 | ```javascript
44 | const car = new Object();
45 | car.brand = "Toyota";
46 | car.model = "Camry";
47 | car.year = 2020;
48 | ```
49 |
50 | ### Доступ к свойствам объекта
51 |
52 | Доступ к свойствам объекта можно получить с помощью точечной нотации или квадратных скобок.
53 |
54 | #### Точечная нотация
55 |
56 | ```javascript
57 | console.log(car.brand); // Toyota
58 | ```
59 |
60 | #### Квадратные скобки
61 |
62 | ```javascript
63 | console.log(car["model"]); // Camry
64 | ```
65 |
66 | ### Изменение свойств объекта
67 |
68 | Свойства объекта можно изменять, присваивая им новые значения.
69 |
70 | ```javascript
71 | car.year = 2021;
72 | console.log(car.year); // 2021
73 | ```
74 |
75 | ### Удаление свойств объекта
76 |
77 | Свойства объекта можно удалять с помощью оператора `delete`.
78 |
79 | ```javascript
80 | delete car.model;
81 | console.log(car.model); // undefined
82 | ```
83 |
84 | ### Методы объекта
85 |
86 | Методы — это функции, которые являются свойствами объекта.
87 |
88 | ```javascript
89 | const person = {
90 | name: "Иван",
91 | greet: function() {
92 | console.log("Привет, " + this.name);
93 | }
94 | };
95 |
96 | person.greet(); // Привет, Иван
97 | ```
98 |
--------------------------------------------------------------------------------
/js/plan.md:
--------------------------------------------------------------------------------
1 | # План поэтапного изучения JavaScript
2 |
3 | ## Урок 1: Типы данных
4 | - **Файл:** `data_types.md`
5 | - **Тема:** Примитивные и объектные типы данных в JavaScript
6 |
7 | ## Урок 2: var, let, const
8 | - **Файл:** `var_let_const.md`
9 | - **Тема:** Способы объявления переменных в JavaScript
10 |
11 | ## Урок 3: Области видимости
12 | - **Файл:** `scope.md`
13 | - **Тема:** Области видимости в JavaScript
14 |
15 | ## Урок 4: Temporal Dead Zone (TDZ) и Hoisting
16 | - **Файл:** `tdz_hoisting.md`
17 | - **Тема:** Поднятие (Hoisting) и временная мертвая зона (TDZ)
18 |
19 | ## Урок 5: Преобразование типов
20 | - **Файл:** `type_conversion.md`
21 | - **Тема:** Явное и неявное преобразование типов
22 |
23 | ## Урок 6: Условные операторы
24 | - **Файл:** `if_else.md`
25 | - **Тема:** Условные операторы в JavaScript
26 |
27 | ## Урок 7: Циклы
28 | - **Файл:** `loops.md`
29 | - **Тема:** Циклы в JavaScript
30 |
31 | ## Урок 8: Функции
32 | - **Файл:** `functions.md`
33 | - **Тема:** Объявление и использование функций в JavaScript
34 |
35 | ## Урок 9: Массивы
36 | - **Файл:** `array.md`
37 | - **Тема:** Работа с массивами и их методами
38 |
39 | ## Урок 10: Мутабельность и иммутабельность
40 | - **Файл:** `mutability_immutability.md`
41 | - **Тема:** Мутабельность и иммутабельность данных в JavaScript
42 |
43 | ## Урок 11: Методы для работы с разными типами данных
44 | - **Файл:** `type_methods.md`
45 | - **Тема:** Методы для работы с числами, строками и датами
46 |
47 | ## Урок 12: Объекты
48 | - **Файл:** `object.md`
49 | - **Тема:** Работа с объектами в JavaScript
50 |
51 |
--------------------------------------------------------------------------------
/js/scope.md:
--------------------------------------------------------------------------------
1 | # Области видимости в JavaScript
2 |
3 | ## Виды областей видимости
4 |
5 | 1. **Глобальная область видимости (Global Scope)**
6 | 2. **Функциональная область видимости (Function Scope)**
7 | 3. **Блочная область видимости (Block Scope)**
8 | 4. **Лексическая область видимости (Lexical Scope)**
9 | 5. **Module scope**
10 |
11 | ## Глобальная область видимости (Global Scope)
12 |
13 | Это область видимости, которая охватывает весь код, за пределами функций и блоков. Все переменные и функции, объявленные в глобальной области видимости, доступны везде в вашем коде.
14 |
15 | ### Пример глобальной области видимости:
16 | ```javascript
17 | let globalVal = "I am global";
18 |
19 | function showGlobal() {
20 | console.log(globalVal); // "I am global"
21 | }
22 | showGlobal();
23 | ```
24 |
25 | ## Функциональная область видимости (Function Scope)
26 |
27 | Переменные, объявленные внутри функции, видны только внутри этой функции. Они не доступны за её пределами.
28 |
29 | ### Пример функциональной области видимости:
30 | ```javascript
31 | function example() {
32 | let funcVar = "I am local to this function";
33 | console.log(funcVar); // "I am local to this function"
34 | }
35 | example();
36 | console.log(funcVar); // ReferenceError: funcVar is not defined
37 | ```
38 |
39 | ## Блочная область видимости (Block Scope)
40 |
41 | Введён в ES6 с помощью `let` и `const`. Переменные, объявленные с помощью `let` или `const` внутри блока кода (например, внутри `{}`), видны только в этом блоке.
42 |
43 | ### Пример блочной области видимости:
44 | ```javascript
45 | if (true) {
46 | let blockVar = "I am block-scoped";
47 | console.log(blockVar); // "I am block-scoped"
48 | }
49 |
50 | console.log(blockVar); // ReferenceError: blockVar is not defined
51 | ```
52 |
53 | ## Лексическая область видимости (Lexical Scope)
54 |
55 | Лексическая область видимости определяется местом, где переменная была объявлена в исходном коде. Вложенные функции имеют доступ к переменным своих внешних функций.
56 |
57 | ### Пример лексической области видимости:
58 | ```javascript
59 | function outer() {
60 | let outerVar = "I am outer";
61 |
62 | function inner() {
63 | console.log(outerVar); // "I am outer"
64 | }
65 | inner();
66 | }
67 | outer();
68 | ```
69 |
70 | ## Module scope
71 |
72 | Переменные и функции, объявленные внутри модуля, не видны за его пределами. Это позволяет избежать загрязнения глобальной области видимости.
73 |
74 | ### Пример module scope:
75 | ```javascript
76 | // module.js
77 | export const moduleVar = "I am module-scoped";
78 |
79 | // main.js
80 | import { moduleVar } from './module.js';
81 | console.log(moduleVar); // "I am module-scoped"
82 | ```
83 |
--------------------------------------------------------------------------------
/js/tdz_hoisting.md:
--------------------------------------------------------------------------------
1 | # Temporal Dead Zone (TDZ) и Hoisting в JavaScript
2 |
3 | ## Temporal Dead Zone (TDZ)
4 |
5 | TDZ — это область блока, в которой переменная недоступна до момента её инициализации. JavaScript выдаст `ReferenceError`, если попытаться получить доступ к переменной до её инициализации.
6 |
7 | ### TDZ применима к следующим конструкциям:
8 | 1. **`let`**
9 | 2. **`const`**
10 | 3. **`class`**
11 |
12 | ### Пример TDZ:
13 | ```javascript
14 | {
15 | // bestFood’s TDZ начинается здесь (в начале области видимости блока)
16 | console.log(bestFood); // ReferenceError, так как bestFood находится в TDZ
17 | let bestFood = "Vegetable Fried Rice"; // bestFood’s TDZ заканчивается здесь
18 | console.log(bestFood); // "Vegetable Fried Rice"
19 | }
20 | ```
21 |
22 | ## Hoisting
23 |
24 | Hoisting в JavaScript означает, что объявления функций и переменных обрабатываются перед выполнением кода. Это означает, что JavaScript даёт более высокий приоритет объявлению переменных, классов и функций во время выполнения программы.
25 |
26 | ### Применимо к:
27 | 1. **Function Declaration:** Объявления функций поднимаются, включая как имя функции, так и её тело. Вы можете вызвать функцию до её фактического объявления.
28 | 2. **`var`:** Объявления переменных поднимаются, но их инициализация остаётся на месте. Переменная будет `undefined` до её инициализации.
29 |
30 | ### Пример Function Declaration:
31 | ```javascript
32 | greet(); // Работает, функция поднята вверх
33 | function greet() {
34 | console.log("Hello!");
35 | }
36 | ```
37 |
38 | ### Пример `var`:
39 | ```javascript
40 | console.log(x); // undefined
41 | var x = 10;
42 | ```
43 |
44 | ## Итог
45 |
46 | | Особенность | `var` | `let` | `const` |
47 | |-------------------------------------|--------------------------------------|------------------------------|------------------------------|
48 | | Область видимости | Функциональная | Блочная | Блочная |
49 | | Всплытие (Hoisting) | Да (инициализируется `undefined`) | Да (но в TDZ) | Да (но в TDZ) |
50 | | Можно переприсваивать | Да | Да | Нет |
51 | | Обязательно задавать значение при объявлении | Нет | Нет | Да |
52 |
53 | Выбор между `var`, `let` и `const` зависит от контекста:
54 | - Используйте `const`, если значение переменной не должно изменяться.
55 | - Используйте `let`, если переменная будет изменяться.
56 | - Не используйте `var`, так как он ведет себя неочевидно из-за всплытия и функциональной области видимости.
57 |
--------------------------------------------------------------------------------
/js/type_conversion.md:
--------------------------------------------------------------------------------
1 | # Преобразование типов в JavaScript
2 |
3 | Преобразование типов в JavaScript включает преобразование значений из одного типа в другой. Это можно сделать явно с помощью различных функций и методов или неявно, когда JavaScript автоматически преобразует значения при выполнении операций, требующих другого типа.
4 |
5 | ## Явное преобразование типов
6 |
7 | Явное преобразование типов происходит, когда вы вручную преобразуете значение из одного типа в другой с помощью встроенных функций и методов.
8 |
9 | ### Преобразование в строку
10 |
11 | Преобразование в строку включает преобразование значений различных типов данных в строку.
12 |
13 | #### Использование функции `String()`
14 |
15 | Функция `String()` преобразует значение в строку.
16 |
17 | ```javascript
18 | let exampleValue = 42;
19 | console.log(typeof exampleValue, exampleValue); // number 42
20 |
21 | exampleValue = String(exampleValue);
22 | console.log(typeof exampleValue, exampleValue); // string "42"
23 |
24 | console.log(String(true)); // "true"
25 | console.log(String(null)); // "null"
26 | console.log(String(undefined)); // "undefined"
27 | console.log(String({})); // "[object Object]"
28 | console.log(String([])); // ""
29 | ```
30 |
31 | #### Использование метода `toString()`
32 |
33 | Метод `toString()` вызывается у объектов для их преобразования в строку.
34 |
35 | ```javascript
36 | console.log((42).toString()); // "42"
37 | console.log(true.toString()); // "true"
38 | console.log([1, 2, 3].toString()); // "1,2,3"
39 | ```
40 |
41 | ### Преобразование в число
42 |
43 | Преобразование в число включает преобразование значений различных типов данных в число.
44 |
45 | #### Использование функции `Number()`
46 |
47 | Функция `Number()` преобразует значение в число.
48 |
49 | ```javascript
50 | console.log(Number("42")); // 42
51 | console.log(Number("42.5")); // 42.5
52 | console.log(Number(true)); // 1
53 | console.log(Number(false)); // 0
54 | console.log(Number(null)); // 0
55 | console.log(Number(undefined)); // NaN
56 | console.log(Number("")); // 0
57 | console.log(Number("abc")); // NaN
58 | ```
59 |
60 | #### Использование функций `parseInt()` и `parseFloat()`
61 |
62 | Функция `parseInt()` парсит строку и возвращает целое число, а `parseFloat()` парсит строку и возвращает число с плавающей точкой.
63 |
64 | ```javascript
65 | console.log(parseInt("42")); // 42
66 | console.log(parseInt("42.5")); // 42
67 | console.log(parseFloat("42.5")); // 42.5
68 | ```
69 |
70 | ### Преобразование в логическое значение
71 |
72 | Преобразование в логическое значение включает преобразование значений различных типов данных в логическое значение.
73 |
74 | #### Использование функции `Boolean()`
75 |
76 | Функция `Boolean()` преобразует значение в логическое.
77 |
78 | ```javascript
79 | console.log(Boolean(1)); // true
80 | console.log(Boolean(0)); // false
81 | console.log(Boolean("hello")); // true
82 | console.log(Boolean("")); // false
83 | console.log(Boolean(null)); // false
84 | console.log(Boolean(undefined)); // false
85 | console.log(Boolean({})); // true
86 | console.log(Boolean([])); // true
87 | ```
88 |
89 | ## Неявное преобразование типов
90 |
91 | Неявное преобразование типов, также известное как приведение типов, происходит, когда JavaScript автоматически преобразует значения из одного типа в другой при выполнении операций, требующих другого типа.
92 |
93 | ### Преобразование в строку
94 |
95 | При использовании оператора `+` со строками и другими типами данных JavaScript автоматически преобразует другие значения в строки.
96 |
97 | ```javascript
98 | console.log("Ответ: " + 42); // "Ответ: 42"
99 | console.log("42" + true); // "42true"
100 | console.log("42" + null); // "42null"
101 | console.log("42" + undefined); // "42undefined"
102 | ```
103 |
104 | ### Преобразование в число
105 |
106 | При использовании арифметических операторов (кроме `+`) с нечисловыми типами JavaScript автоматически преобразует другие значения в числа.
107 |
108 | ```javascript
109 | console.log("42" - 10); // 32
110 | console.log("42" * 2); // 84
111 | console.log("42" / 2); // 21
112 | console.log("42" - true); // 41
113 | console.log("42" - null); // 42
114 | console.log("42" - undefined); // NaN
115 | ```
116 |
117 | ### Преобразование в логическое значение
118 |
119 | В логических операциях JavaScript автоматически преобразует значения в логические.
120 |
121 | ```javascript
122 | console.log(!!"hello"); // true
123 | console.log(!!""); // false
124 | console.log(!!42); // true
125 | console.log(!!0); // false
126 | console.log(!!null); // false
127 | console.log(!!undefined); // false
128 | console.log(!!{}); // true
129 | console.log(!![]); // true
130 | ```
131 |
132 | ### Значения которые при преобразовании будут false, в остальных случаях true:
133 | - `0`
134 | - `null`
135 | - `undefined`
136 | - `NaN`
137 | - `""`
138 |
--------------------------------------------------------------------------------
/js/type_methods.md:
--------------------------------------------------------------------------------
1 | # Работа с числами (Number)
2 |
3 | ## Округление
4 |
5 | - `Math.round(num)` – округление до ближайшего целого.
6 | - `Math.floor(num)` – округление вниз.
7 | - `Math.ceil(num)` – округление вверх.
8 | - `Math.trunc(num)` – убирает дробную часть.
9 |
10 | ### Примеры:
11 |
12 | ```javascript
13 | console.log(Math.round(4.5)); // 5
14 | console.log(Math.floor(4.5)); // 4
15 | console.log(Math.ceil(4.5)); // 5
16 | console.log(Math.trunc(4.5)); // 4
17 | ```
18 |
19 | ## Генерация случайного числа
20 |
21 | - `Math.random()` – случайное число от 0 до 1.
22 |
23 | ### Примеры:
24 |
25 | ```javascript
26 | console.log(Math.random()); // Например: 0.675312
27 | ```
28 |
29 | ## Математические операции
30 |
31 | - `Math.max(a, b, ...)` / `Math.min(a, b, ...)` – наибольшее/наименьшее из списка.
32 | - `Math.pow(base, exp)` – возведение в степень.
33 | - `Math.sqrt(num)` – квадратный корень.
34 |
35 | ### Примеры:
36 |
37 | ```javascript
38 | console.log(Math.max(1, 5, 10, 99)); // 99
39 | console.log(Math.min(1, 5, 10, 0, -10)); // -10
40 | console.log(Math.pow(2, 4)); // 16
41 | console.log(Math.sqrt(36)); // 6
42 | ```
43 |
44 | ## Преобразования
45 |
46 | - `Number.parseInt(str)` – преобразует строку в целое число.
47 | - `Number.parseFloat(str)` – преобразует строку в число с плавающей точкой.
48 | - `num.toFixed(digits)` – округляет число до указанного количества знаков после запятой (возвращает строку).
49 |
50 | ### Примеры:
51 |
52 | ```javascript
53 | console.log(Number.parseInt("42px")); // 42
54 | console.log(Number.parseFloat("42.5px")); // 42.5
55 | console.log((5.56589).toFixed(2)); // "5.57"
56 | ```
57 |
58 | # Работа со строками (String)
59 |
60 | ## Получение длины
61 |
62 | - `str.length` – длина строки.
63 |
64 | ### Примеры:
65 |
66 | ```javascript
67 | let str = "Hello";
68 | console.log(str.length); // 5
69 | ```
70 |
71 | ## Преобразование регистра
72 |
73 | - `str.toUpperCase()` – в верхний регистр.
74 | - `str.toLowerCase()` – в нижний регистр.
75 |
76 | ### Примеры:
77 |
78 | ```javascript
79 | console.log(str.toUpperCase()); // "HELLO"
80 | console.log(str.toLowerCase()); // "hello"
81 | ```
82 |
83 | ## Поиск
84 |
85 | - `str.indexOf(substr)` – индекс первого вхождения подстроки.
86 | - `str.lastIndexOf(substr)` – индекс последнего вхождения.
87 | - `str.includes(substr)` – проверяет, содержит ли строка подстроку (возвращает true/false).
88 | - `str.startsWith(substr)` / `str.endsWith(substr)` – проверяет начало/конец строки.
89 |
90 | ### Примеры:
91 |
92 | ```javascript
93 | console.log(str.indexOf("l")); // 2
94 | console.log(str.lastIndexOf("l")); // 3
95 | console.log(str.includes("lo")); // true
96 | console.log(str.startsWith("He")); // true
97 | console.log(str.endsWith("o")); // true
98 | ```
99 |
100 | ## Извлечение подстроки
101 |
102 | - `str.slice(start, end)` – извлекает часть строки.
103 | - `str.substring(start, end)` – извлекает подстроку.
104 | - `str.substr(start, length)` – извлекает подстроку заданной длины (устарело).
105 |
106 | ### Примеры:
107 |
108 | ```javascript
109 | console.log(str.slice(1, 4)); // "ell"
110 | console.log(str.substring(1, 4)); // "ell"
111 | console.log(str.substr(1, 3)); // "ell" (устарело)
112 | ```
113 |
114 | ## Модификация
115 |
116 | - `str.trim()` – убирает пробелы в начале и конце строки.
117 | - `str.replace(substr, newSubstr)` – заменяет подстроку.
118 | - `str.split(delimiter)` – разделяет строку на массив по разделителю.
119 |
120 | ### Примеры:
121 |
122 | ```javascript
123 | let strWithSpaces = " Hello World ";
124 | console.log(strWithSpaces.trim()); // "Hello World"
125 |
126 | console.log(str.replace("World", "JavaScript")); // "Hello JavaScript"
127 |
128 | console.log(str.split("")); // ["H", "e", "l", "l", "o"]
129 | ```
130 |
131 | # Работа с датами (Date)
132 |
133 | ## Создание даты
134 |
135 | - `new Date()` – текущая дата и время.
136 | - `new Date(ms)` – дата на основе миллисекунд с 1970 года.
137 | - `new Date("YYYY-MM-DD")` – создание даты из строки.
138 |
139 | ### Примеры:
140 |
141 | ```javascript
142 | let now = new Date();
143 | console.log(now); // Текущая дата и время
144 |
145 | let specificDate = new Date(0);
146 | console.log(specificDate); // 1970-01-01T00:00:00.000Z
147 |
148 | let stringDate = new Date("2024-11-19");
149 | console.log(stringDate); // 2024-11-19T00:00:00.000Z
150 | ```
151 |
152 | ## Получение частей даты
153 |
154 | - `date.getFullYear()` – год.
155 | - `date.getMonth()` – месяц (0–11).
156 | - `date.getDate()` – день месяца.
157 | - `date.getDay()` – день недели (0–6).
158 | - `date.getHours()`, `date.getMinutes()`, `date.getSeconds()` – время.
159 |
160 | ### Примеры:
161 |
162 | ```javascript
163 | console.log(now.getFullYear()); // Например: 2024
164 | console.log(now.getMonth()); // 10 (Ноябрь, так как месяцы от 0)
165 | console.log(now.getDate()); // 19
166 | console.log(now.getDay()); // 2 (вторник)
167 | console.log(now.getHours()); // Часы
168 | console.log(now.getMinutes()); // Минуты
169 | console.log(now.getSeconds()); // Секунды
170 | ```
171 |
172 | ## Преобразование
173 |
174 | - `date.toISOString()` – дата в формате ISO.
175 | - `date.toLocaleString()` – локализованный формат даты и времени.
176 |
177 | ### Примеры:
178 |
179 | ```javascript
180 | console.log(now.toISOString()); // "2024-11-19T12:00:00.000Z"
181 | console.log(now.toLocaleString()); // Локализованный формат
182 | ```
183 |
184 | ## Изменение даты
185 |
186 | - `date.setFullYear(year)` – изменить год.
187 | - `date.setMonth(month)` – изменить месяц.
188 | - `date.setDate(day)` – изменить день.
189 |
190 | ### Примеры:
191 |
192 | ```javascript
193 | now.setFullYear(2025);
194 | console.log(now.getFullYear()); // 2025
195 |
196 | now.setMonth(0);
197 | console.log(now.getMonth()); // 0 (январь)
198 |
199 | now.setDate(1);
200 | console.log(now.getDate()); // 1
201 | ```
--------------------------------------------------------------------------------
/js/var_let_const.md:
--------------------------------------------------------------------------------
1 | # Способы объявления переменных в JavaScript
2 |
3 | ## `var`
4 |
5 | Переменные, объявленные с `var`, имеют функциональную область видимости (или глобальную, если не находятся в функции) и могут быть переопределены.
6 |
7 | ### Особенности `var`:
8 | - **Функциональная область видимости:** Переменные, объявленные с `var`, видимы в пределах функции, игнорируя блочную область видимости. Если `var` объявлен вне функции, он становится глобальным.
9 | - **Всплытие (Hoisting):** Переменные `var` всплывают в начало своей области видимости. Это позволяет использовать их до объявления, но их значение будет `undefined` до присваивания.
10 | - **Повторное объявление:** Переменные `var` можно объявлять несколько раз в одной области видимости.
11 |
12 | ### Пример использования `var`:
13 | ```javascript
14 | var imVar = "im var variant value";
15 | console.log(imVar); // "im var variant value"
16 |
17 | imVar = "im another value of imVar";
18 | console.log(imVar); // "im another value of imVar"
19 | ```
20 |
21 | ## `let` и `const`
22 |
23 | Переменные, объявленные с `let` и `const`, имеют блочную область видимости.
24 |
25 | ### Общие особенности `let` и `const`:
26 | - **Блочная область видимости:** Доступны только внутри блока, в котором были объявлены.
27 | - **Temporal Dead Zone (TDZ):** `let` и `const` всплывают (hoisting), но остаются в "Temporal Dead Zone" до фактического выполнения их объявления. Доступ к таким переменным до их объявления вызовет `ReferenceError`, в отличие от `var`, который инициализируется как `undefined`.
28 |
29 | ## `let`
30 |
31 | Переменная, объявленная с `let`, может быть переприсвоена позже.
32 | - Переменная может быть объявлена без начального значения, инициализация может произойти позже.
33 | - Допускается изменение типа данных переменной.
34 |
35 | ### Пример использования `let`:
36 | ```javascript
37 | let imLet = "im let variant value";
38 | imLet = "im another value of imVar";
39 | console.log(imLet); // "im another value of imVar"
40 | ```
41 |
42 | ## `const`
43 |
44 | Переменная, объявленная с `const`, не может быть переприсвоена.
45 | - Обязательная инициализация при объявлении.
46 | - Смена типа данных переменной невозможна, но можно изменять свойства объекта, если `const` ссылается на объект.
47 |
48 | ### Пример использования `const`:
49 | ```javascript
50 | const imConst = "im const variant value";
51 | console.log(imConst); // "im const variant value"
52 |
53 | // Ошибка: переприсваивание невозможно
54 | // imConst = "new value"; // TypeError
55 | ```
56 |
57 | ## Итог
58 |
59 | | Особенность | `var` | `let` | `const` |
60 | |-------------------------------------|--------------------------------------|------------------------------|------------------------------|
61 | | Область видимости | Функциональная | Блочная | Блочная |
62 | | Всплытие (Hoisting) | Да (инициализируется `undefined`) | Да (но в TDZ) | Да (но в TDZ) |
63 | | Можно переприсваивать | Да | Да | Нет |
64 | | Обязательно задавать значение при объявлении | Нет | Нет | Да |
65 |
66 | Выбор между `var`, `let` и `const` зависит от контекста:
67 | - Используйте `const`, если значение переменной не должно изменяться.
68 | - Используйте `let`, если переменная будет изменяться.
69 | - Не используйте `var`, так как он ведет себя неочевидно из-за всплытия и функциональной области видимости.
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/.eslintrc.js:
--------------------------------------------------------------------------------
1 | // https://docs.expo.dev/guides/using-eslint/
2 | module.exports = {
3 | extends: "expo",
4 | };
5 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
17 | # The following patterns were generated by expo-cli
18 |
19 | expo-env.d.ts
20 | # @end expo-cli
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to your Expo app 👋
2 |
3 | This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
4 |
5 | ## Get started
6 |
7 | 1. Install dependencies
8 |
9 | ```bash
10 | npm install
11 | ```
12 |
13 | 2. Start the app
14 |
15 | ```bash
16 | npx expo start
17 | ```
18 |
19 | In the output, you'll find options to open the app in a
20 |
21 | - [development build](https://docs.expo.dev/develop/development-builds/introduction/)
22 | - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
23 | - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
24 | - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
25 |
26 | You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
27 |
28 | ## Get a fresh project
29 |
30 | When you're ready, run:
31 |
32 | ```bash
33 | npm run reset-project
34 | ```
35 |
36 | This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
37 |
38 | ## Learn more
39 |
40 | To learn more about developing your project with Expo, look at the following resources:
41 |
42 | - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
43 | - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
44 |
45 | ## Join the community
46 |
47 | Join our community of developers creating universal apps.
48 |
49 | - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
50 | - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
51 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "BMI_Calc",
4 | "slug": "BMI_Calc",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/images/icon.png",
8 | "scheme": "myapp",
9 | "userInterfaceStyle": "automatic",
10 | "splash": {
11 | "image": "./assets/images/splash.png",
12 | "resizeMode": "contain",
13 | "backgroundColor": "#ffffff"
14 | },
15 | "ios": {
16 | "supportsTablet": true
17 | },
18 | "android": {
19 | "adaptiveIcon": {
20 | "foregroundImage": "./assets/images/adaptive-icon.png",
21 | "backgroundColor": "#ffffff"
22 | }
23 | },
24 | "web": {
25 | "bundler": "metro",
26 | "output": "static",
27 | "favicon": "./assets/images/favicon.png"
28 | },
29 | "plugins": [
30 | "expo-router"
31 | ],
32 | "experiments": {
33 | "typedRoutes": true
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Stack } from "expo-router";
2 | import React from "react";
3 |
4 | export default function Layout() {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/app/calculate-bmi.tsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { Text, View, StyleSheet } from "react-native";
3 |
4 | import React from "react";
5 | import Slider from "@react-native-community/slider";
6 | import { calculateBMI } from "../helpers/functions/calculateBMI";
7 | import IncrementDecrementControl from "@widget/IncrementDecrementControl/IncrementDecrementControl";
8 | import LinkButton from "@base/Button/Button";
9 | import Switcher from "@base/Switcher/Switcher";
10 |
11 | const MIN_HEIGHT = 30;
12 | const MAX_HEIGHT = 300;
13 |
14 | const CalculateBmiScreen = () => {
15 | const [age, setAge] = useState(30);
16 | const [weight, setWeight] = useState(60);
17 | const [isManGender, setIsManGender] = useState(true);
18 | const [height, setHeight] = useState(175);
19 |
20 | return (
21 |
22 | BMI CALCULATOR
23 |
24 |
25 |
30 |
31 |
32 | Height (CM)
33 | {height}
34 |
45 |
46 | {MIN_HEIGHT} cm
47 | {MAX_HEIGHT} cm
48 |
49 |
50 |
51 | Gender
52 |
53 | Male
54 |
55 | Female
56 |
57 |
58 |
67 |
68 | );
69 | };
70 |
71 | const styles = StyleSheet.create({
72 | container: {
73 | paddingHorizontal: 30,
74 | flex: 1,
75 | justifyContent: "center",
76 | alignItems: "center",
77 | backgroundColor: "#F4F3FF",
78 | },
79 | title: {
80 | textAlign: "center",
81 | lineHeight: 21,
82 | fontSize: 17.6,
83 | color: "#081854",
84 | },
85 | row: {
86 | flexDirection: "row",
87 | gap: 21,
88 | marginTop: 39,
89 | },
90 | heightText: {
91 | fontSize: 57.4,
92 | lineHeight: 69,
93 | color: "#6C63FF",
94 | fontWeight: "700",
95 | textAlign: "center",
96 | },
97 | sliderStyle: { width: "100%", height: 40 },
98 | limitsWrapper: { justifyContent: "space-between", flexDirection: "row" },
99 | limitText: {
100 | fontSize: 13,
101 | lineHeight: 16,
102 | color: "#060918",
103 | },
104 | blockTitle: {
105 | fontSize: 17.6,
106 | lineHeight: 21,
107 | textAlign: "center",
108 | color: "#081854",
109 | },
110 |
111 | blockWrapper: {
112 | marginTop: 23,
113 | width: "100%",
114 | paddingTop: 17,
115 | paddingHorizontal: 36,
116 | paddingBottom: 24,
117 | backgroundColor: "#ffffff",
118 | borderRadius: 12,
119 | },
120 |
121 | blockRow: {
122 | marginTop: 26,
123 | flexDirection: "row",
124 | gap: 18,
125 | alignItems: "center",
126 | },
127 |
128 | button: {
129 | marginTop: 38,
130 | },
131 | });
132 |
133 | export default CalculateBmiScreen;
134 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/app/index.tsx:
--------------------------------------------------------------------------------
1 | import { Text, View, StyleSheet } from "react-native";
2 | import { Image } from "expo-image";
3 | import React from "react";
4 | import LinkButton from "@base/Button/Button";
5 | function Index() {
6 | return (
7 |
8 |
13 |
18 | Get Started with Tracking Your Health!
19 |
20 | Calculate your BMI and stay on top of your wellness journey,
21 | effortlessly.
22 |
23 |
30 |
31 | );
32 | }
33 |
34 | const styles = StyleSheet.create({
35 | container: {
36 | backgroundColor: "#6C63FF",
37 | flex: 1,
38 | justifyContent: "center",
39 | paddingHorizontal: 30,
40 | alignItems: "center",
41 | },
42 | textImage: {
43 | width: 104,
44 | height: 37,
45 | },
46 | mainImage: {
47 | width: 296,
48 | height: 251,
49 | marginTop: 59,
50 | },
51 | heading: {
52 | color: "#FFFFFF",
53 |
54 | marginTop: 95,
55 | fontWeight: "700",
56 | fontSize: 25,
57 | lineHeight: 33,
58 | },
59 | subText: {
60 | color: "#FFFFFF",
61 |
62 | fontSize: 15,
63 | lineHeight: 19,
64 | marginTop: 15,
65 | },
66 | button: {
67 | marginTop: 38,
68 | },
69 | });
70 |
71 | export default Index;
72 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/app/result.tsx:
--------------------------------------------------------------------------------
1 | import { View, StyleSheet, Text, Alert, TouchableOpacity } from "react-native";
2 | import React, { useRef } from "react";
3 | import { router, useLocalSearchParams } from "expo-router";
4 | import * as MediaLibrary from "expo-media-library";
5 | import { captureRef } from "react-native-view-shot";
6 | import { Image } from "expo-image";
7 | import { resultToText } from "@functions/resultToText";
8 | import LinkButton from "@base/Button/Button";
9 |
10 | const ResultScreen = () => {
11 | const { result } = useLocalSearchParams<{ result: string }>();
12 |
13 | const imageRef = useRef(null);
14 |
15 | const [status, requestPermission] = MediaLibrary.usePermissions();
16 |
17 | const [integerPart, decimalPart] = result.split(".");
18 |
19 | const onSaveImageAsync = async () => {
20 | if (!status) {
21 | await requestPermission();
22 | }
23 |
24 | try {
25 | const localUri = await captureRef(imageRef, {
26 | height: 440,
27 | quality: 1,
28 | });
29 |
30 | if (localUri) {
31 | await MediaLibrary.saveToLibraryAsync(localUri);
32 | showAlert(
33 | "Success!",
34 | "Your BMI has been successfully saved! What would you like to do next?"
35 | );
36 | }
37 | } catch (error) {
38 | showAlert("Ops...!", `Some error: ${error}`);
39 | }
40 | };
41 |
42 | const showAlert = (title: string, message: string) => {
43 | Alert.alert(title, message, [
44 | {
45 | text: "Go Back",
46 | onPress: () => router.back(),
47 | style: "destructive",
48 | },
49 | {
50 | text: "Close alert",
51 | style: "default",
52 | },
53 | ]);
54 | };
55 |
56 | return (
57 |
58 | router.back()}
60 | style={{
61 | position: "absolute",
62 | top: 40,
63 | left: 20,
64 | }}
65 | >
66 |
74 |
75 | BMI CALCULATOR
76 | Body Mass Index
77 |
78 | BMI Results
79 |
80 | {integerPart}
81 | .{decimalPart}
82 |
83 | {resultToText(result)}
84 |
85 | Underweight: BMI less than 18.5{`\n`}
86 | Normal weight: BMI 18.5 to 24.9{`\n`}
87 | Overweight: BMI 25 to 29.9{`\n`}
88 | Obesity: 30 to 40
89 |
90 |
91 |
97 |
98 | );
99 | };
100 |
101 | const styles = StyleSheet.create({
102 | container: {
103 | paddingHorizontal: 30,
104 | flex: 1,
105 | justifyContent: "center",
106 | alignItems: "center",
107 | backgroundColor: "#F4F3FF",
108 | },
109 | title: {
110 | textAlign: "center",
111 | lineHeight: 21,
112 | fontSize: 17.6,
113 | color: "#081854",
114 | },
115 |
116 | resultContainer: {
117 | marginTop: 42,
118 | backgroundColor: "#ffffff",
119 | paddingHorizontal: 43,
120 | paddingTop: 45,
121 | paddingBottom: 37,
122 | borderRadius: 12,
123 | width: "100%",
124 | },
125 |
126 | headerText: {
127 | marginTop: 35,
128 | fontSize: 27.8,
129 | lineHeight: 34,
130 | textAlign: "center",
131 | color: "#081854",
132 | },
133 | resultTitle: {
134 | fontSize: 32.7,
135 | lineHeight: 40,
136 | textAlign: "center",
137 | color: "#081854",
138 | },
139 |
140 | numberWrapper: {
141 | flexDirection: "row",
142 | alignItems: "flex-end",
143 | justifyContent: "center",
144 | },
145 | bigNumber: {
146 | fontWeight: "700",
147 | fontSize: 140.633,
148 | lineHeight: 170,
149 | color: "#6C63FF",
150 | },
151 | smallNumbers: {
152 | fontWeight: "500",
153 | fontSize: 42.2,
154 | lineHeight: 51,
155 | color: "#6C63FF",
156 | textAlign: "center",
157 | marginBottom: 27.5,
158 | },
159 |
160 | typeBmiText: {
161 | fontWeight: "500",
162 | fontSize: 24,
163 | lineHeight: 26,
164 | textAlign: "center",
165 |
166 | color: "#081854",
167 | },
168 |
169 | noteText: {
170 | marginTop: 18.5,
171 | textAlign: "center",
172 | fontWeight: "500",
173 | fontSize: 13,
174 | lineHeight: 20,
175 | color: "#081854",
176 | },
177 |
178 | button: { marginTop: 50 },
179 | });
180 |
181 | export default ResultScreen;
182 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/BMI_Calc/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/back-icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/BMI_Calc/assets/images/favicon.png
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/BMI_Calc/assets/images/icon.png
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/mainImg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/BMI_Calc/assets/images/mainImg.png
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/minus.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/plus.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/BMI_Calc/assets/images/splash.png
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/assets/images/textImg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/BMI_Calc/assets/images/textImg.png
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/components/base/Button/Button.tsx:
--------------------------------------------------------------------------------
1 | import { Href, router } from "expo-router";
2 | import React from "react";
3 | import {
4 | StyleSheet,
5 | StyleProp,
6 | TextStyle,
7 | Text,
8 | TouchableOpacity,
9 | } from "react-native";
10 |
11 | type ButtonProps = {
12 | textLink: string;
13 | href?: Href;
14 | variant?: "purple" | "white";
15 | replace?: boolean;
16 | styleButton?: StyleProp;
17 | styleTextButton?: StyleProp;
18 | disabled?: boolean;
19 | onPress?: () => void;
20 | };
21 |
22 | const LinkButton = ({
23 | disabled,
24 | href,
25 | styleButton,
26 | variant,
27 | textLink,
28 | replace,
29 | onPress,
30 | }: ButtonProps) => {
31 | const handleNavigation = () => {
32 | if (!href) return;
33 |
34 | if (replace) {
35 | router.replace(href);
36 | } else {
37 | router.push(href);
38 | }
39 | };
40 |
41 | return (
42 |
51 |
57 | {textLink}
58 |
59 |
60 | );
61 | };
62 |
63 | const styles = StyleSheet.create({
64 | button: {
65 | backgroundColor: "#6C63FF",
66 | width: "100%",
67 | alignItems: "center",
68 | justifyContent: "center",
69 | borderRadius: 63,
70 | overflow: "hidden",
71 | paddingVertical: 27,
72 | },
73 | buttonText: {
74 | color: "#FFFFFF",
75 | borderRadius: 63,
76 | fontWeight: 500,
77 | fontSize: 17.6,
78 | lineHeight: 21,
79 | textAlign: "center",
80 | },
81 | buttonWhite: {
82 | backgroundColor: "#F4F3FF",
83 | },
84 | buttonWhiteText: {
85 | color: "#081854",
86 | },
87 | });
88 | export default LinkButton;
89 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/components/base/Switcher/Switcher.tsx:
--------------------------------------------------------------------------------
1 | import React, { useRef } from "react";
2 | import { View, Pressable, Animated } from "react-native";
3 |
4 | interface SwitchProps {
5 | onChange: (newMode: boolean) => void;
6 | switchColor?: string;
7 | value: boolean;
8 | }
9 |
10 | const Switcher = ({ onChange, value }: SwitchProps) => {
11 | const left = useRef(new Animated.Value(0)).current;
12 |
13 | const handlePress = (newMode: boolean) => {
14 | Animated.timing(left, {
15 | toValue: !value ? 0 : 1,
16 | duration: 200,
17 | useNativeDriver: false,
18 | }).start();
19 | onChange(newMode);
20 | };
21 |
22 | return (
23 |
34 |
50 | handlePress(false)}
52 | style={[
53 | {
54 | flex: 1,
55 | width: "50%",
56 | justifyContent: "center",
57 | alignItems: "center",
58 | },
59 | ]}
60 | >
61 | handlePress(true)}
63 | style={[
64 | {
65 | flex: 1,
66 | width: "50%",
67 | justifyContent: "center",
68 | alignItems: "center",
69 | },
70 | ]}
71 | >
72 |
73 | );
74 | };
75 |
76 | export default Switcher;
77 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/components/widgets/IncrementDecrementControl/IncrementDecrementControl.tsx:
--------------------------------------------------------------------------------
1 | import { Text, TouchableOpacity, View, StyleSheet } from "react-native";
2 | import { Image } from "expo-image";
3 | import React from "react";
4 |
5 | interface IncrementDecrementControlProps {
6 | label: string;
7 | value: number;
8 | setValue: React.Dispatch>;
9 | }
10 |
11 | const IncrementDecrementControl = ({
12 | label,
13 | value,
14 | setValue,
15 | }: IncrementDecrementControlProps) => {
16 | return (
17 |
18 | {label}
19 | {value}
20 |
21 | value > 0 && setValue((prev) => prev - 1)}
25 | >
26 |
31 |
32 | setValue((prev) => prev + 1)}
35 | >
36 |
41 |
42 |
43 |
44 | );
45 | };
46 |
47 | const styles = StyleSheet.create({
48 | box: {
49 | paddingBottom: 14,
50 | flex: 1,
51 | paddingTop: 27,
52 | backgroundColor: "#ffffff",
53 | borderRadius: 12,
54 | justifyContent: "center",
55 | },
56 | label: {
57 | fontSize: 17.6,
58 | lineHeight: 21,
59 | color: "#2fe41",
60 | textAlign: "center",
61 | },
62 | value: {
63 | marginTop: 3,
64 | fontSize: 57.4,
65 | lineHeight: 69,
66 | color: "#6C63FF",
67 | fontWeight: "700",
68 | textAlign: "center",
69 | },
70 | buttonGroup: {
71 | flexDirection: "row",
72 | gap: 31.6,
73 | alignSelf: "center",
74 | },
75 | button: {
76 | backgroundColor: "#081854",
77 | borderRadius: 100,
78 | padding: 8.4,
79 | alignSelf: "center",
80 | },
81 | buttonDismiss: {
82 | opacity: 0.6,
83 | },
84 | icon: {
85 | width: 17.6,
86 | height: 17.6,
87 | },
88 | });
89 |
90 | export default IncrementDecrementControl;
91 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/helpers/functions/calculateBMI.tsx:
--------------------------------------------------------------------------------
1 | export const calculateBMI = (
2 | age: number,
3 | weight: number,
4 | height: number,
5 | isManGender: boolean
6 | ): string => {
7 | const heightInMeters = height / 100;
8 | const bmi = weight / heightInMeters ** 2;
9 |
10 | let adjustmentFactor = 1;
11 |
12 | if (isManGender) {
13 | if (age < 30) {
14 | adjustmentFactor = 0.98;
15 | } else if (age < 50) {
16 | adjustmentFactor = 1.0;
17 | } else {
18 | adjustmentFactor = 1.02;
19 | }
20 | } else {
21 | if (age < 30) {
22 | adjustmentFactor = 0.95;
23 | } else if (age < 50) {
24 | adjustmentFactor = 1.0;
25 | } else {
26 | adjustmentFactor = 1.05;
27 | }
28 | }
29 |
30 | return (bmi * adjustmentFactor).toFixed(2);
31 | };
32 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/helpers/functions/resultToText.ts:
--------------------------------------------------------------------------------
1 | export const resultToText = (result: string): string => {
2 | const numericBmi = parseFloat(result);
3 |
4 | switch (true) {
5 | case numericBmi < 18.5:
6 | return "Underweight";
7 | case numericBmi >= 18.5 && numericBmi < 24.9:
8 | return "Normal weight";
9 |
10 | case numericBmi >= 25 && numericBmi < 29.9:
11 | return "Overweight";
12 |
13 | case numericBmi >= 30:
14 | return "Obesity";
15 | default:
16 | return "Invalid BMI value";
17 | }
18 | };
19 |
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bmi_calc",
3 | "main": "expo-router/entry",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "lint": "expo lint"
10 | },
11 | "dependencies": {
12 | "@expo/vector-icons": "^14.0.2",
13 | "@react-native-community/slider": "^4.5.3",
14 | "@react-navigation/native": "^6.0.2",
15 | "ajv": "^8.17.1",
16 | "expo": "~51.0.28",
17 | "expo-constants": "~16.0.2",
18 | "expo-image": "~1.13.0",
19 | "expo-media-library": "~16.0.5",
20 | "expo-router": "~3.5.23",
21 | "react": "18.2.0",
22 | "react-dom": "18.2.0",
23 | "react-native": "0.74.5",
24 | "react-native-screens": "3.31.1",
25 | "react-native-view-shot": "3.8.0",
26 | "expo-status-bar": "~1.12.1",
27 | "react-native-safe-area-context": "4.10.5",
28 | "expo-linking": "~6.3.1"
29 | },
30 | "devDependencies": {
31 | "@babel/cli": "^7.25.7",
32 | "@babel/core": "^7.25.7",
33 | "@babel/preset-env": "^7.25.7",
34 | "@types/react": "~18.2.45",
35 | "eslint": "^8.57.0",
36 | "eslint-config-expo": "^7.1.2",
37 | "eslint-plugin-jsx-a11y": "^6.10.0",
38 | "typescript": "~5.3.3"
39 | },
40 | "private": true
41 | }
--------------------------------------------------------------------------------
/mobile_apps/BMI_Calc/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "jsx": "react",
5 | "strict": true,
6 | "paths": {
7 | "@base/*": ["./components/base/*"],
8 | "@widget/*": ["./components/widgets/*"],
9 | "@hooks/*": ["./helpers/hooks/*"],
10 | "@functions/*": ["./helpers/functions/*"],
11 | }
12 | },
13 | "include": [
14 | "**/*.ts",
15 | "**/*.tsx",
16 | ".expo/types/**/*.ts",
17 | "expo-env.d.ts"
18 | ]
19 | }
20 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .expo/
3 | dist/
4 | npm-debug.*
5 | *.jks
6 | *.p8
7 | *.p12
8 | *.key
9 | *.mobileprovision
10 | *.orig.*
11 | web-build/
12 |
13 | # macOS
14 | .DS_Store
15 |
16 | # @generated expo-cli sync-2b81b286409207a5da26e14c78851eb30d8ccbdb
17 | # The following patterns were generated by expo-cli
18 |
19 | expo-env.d.ts
20 | # @end expo-cli
--------------------------------------------------------------------------------
/mobile_apps/weather-app/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to your Expo app 👋
2 |
3 | This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app).
4 |
5 | ## Get started
6 |
7 | 1. Install dependencies
8 |
9 | ```bash
10 | npm install
11 | ```
12 |
13 | 2. Start the app
14 |
15 | ```bash
16 | npx expo start
17 | ```
18 |
19 | In the output, you'll find options to open the app in a
20 |
21 | - [development build](https://docs.expo.dev/develop/development-builds/introduction/)
22 | - [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/)
23 | - [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/)
24 | - [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo
25 |
26 | You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction).
27 |
28 | ## Get a fresh project
29 |
30 | When you're ready, run:
31 |
32 | ```bash
33 | npm run reset-project
34 | ```
35 |
36 | This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
37 |
38 | ## Learn more
39 |
40 | To learn more about developing your project with Expo, look at the following resources:
41 |
42 | - [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides).
43 | - [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web.
44 |
45 | ## Join the community
46 |
47 | Join our community of developers creating universal apps.
48 |
49 | - [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute.
50 | - [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions.
51 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/api/url.ts:
--------------------------------------------------------------------------------
1 | export const API_KEY = process.env.EXPO_PUBLIC_API_KEY;
2 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "weather-app",
4 | "slug": "weather-app",
5 | "version": "1.0.0",
6 | "orientation": "portrait",
7 | "icon": "./assets/images/icon.png",
8 | "scheme": "myapp",
9 | "userInterfaceStyle": "automatic",
10 | "splash": {
11 | "image": "./assets/images/splash.png",
12 | "resizeMode": "contain",
13 | "backgroundColor": "#ffffff"
14 | },
15 | "ios": {
16 | "supportsTablet": true
17 | },
18 | "android": {
19 | "adaptiveIcon": {
20 | "foregroundImage": "./assets/images/adaptive-icon.png",
21 | "backgroundColor": "#ffffff"
22 | }
23 | },
24 | "web": {
25 | "bundler": "metro",
26 | "output": "static",
27 | "favicon": "./assets/images/favicon.png"
28 | },
29 | "plugins": [
30 | "expo-router"
31 | ],
32 | "experiments": {
33 | "typedRoutes": true
34 | },
35 | "extra": {
36 | "router": {
37 | "origin": false
38 | },
39 | "eas": {
40 | "projectId": "e7c4bca1-d066-4e8a-b50e-8361c1218a8e"
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/app/_layout.tsx:
--------------------------------------------------------------------------------
1 | import { Stack } from "expo-router";
2 | import React from "react";
3 |
4 | export default function Layout() {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/app/index.tsx:
--------------------------------------------------------------------------------
1 | import { StyleSheet, Text, View, Image } from "react-native";
2 | import * as Location from "expo-location";
3 | import { useEffect, useState } from "react";
4 | import { FontAwesome5, Ionicons } from "@expo/vector-icons";
5 | import useCurrentPositionWeather from "../hooks/useCurrentPositionWeather";
6 | import { WeatherData } from "../types";
7 | import useCityWeather from "../hooks/useCityWeather";
8 | import InputSearch from "../components/SearchInput";
9 |
10 | export default function Index() {
11 | const [currentWeatherData, setCurrentWeatherData] = useState();
12 |
13 | const [myLocation, setMyLocation] = useState<{
14 | latitude?: number;
15 | longitude?: number;
16 | }>({
17 | latitude: undefined,
18 | longitude: undefined,
19 | });
20 |
21 | const [searchValue, setSearchValue] = useState("");
22 |
23 | const {
24 | data: cityData,
25 | isLoading: cityIsLoading,
26 | isError: cityIsError,
27 | } = useCityWeather(searchValue);
28 |
29 | const { data, isLoading, isError } = useCurrentPositionWeather({
30 | latitude: myLocation.latitude,
31 | longitude: myLocation.longitude,
32 | });
33 |
34 | const error = isError || cityIsError;
35 | const loading = isLoading || cityIsLoading;
36 |
37 | useEffect(() => {
38 | getLocationPermissions();
39 | }, []);
40 |
41 | useEffect(() => {
42 | if (data) {
43 | setCurrentWeatherData(data);
44 | }
45 | }, [data]);
46 |
47 | useEffect(() => {
48 | if (cityData) {
49 | setCurrentWeatherData(cityData);
50 | }
51 | }, [cityData]);
52 |
53 | const getLocationPermissions = async () => {
54 | const { status } = await Location.requestForegroundPermissionsAsync();
55 |
56 | if (status !== "granted") {
57 | console.log("Permission to access location was denied");
58 | return;
59 | }
60 |
61 | const {
62 | coords: { latitude, longitude },
63 | } = await Location.getCurrentPositionAsync({});
64 |
65 | setMyLocation({ latitude, longitude });
66 | };
67 |
68 | const handleSetCityWeatherData = () => {
69 | if (cityData) {
70 | setCurrentWeatherData(cityData);
71 | }
72 | };
73 |
74 | const handleSetCurrentWeatherData = () => {
75 | if (data) {
76 | setCurrentWeatherData(data);
77 | }
78 | };
79 |
80 | return (
81 |
82 | {currentWeatherData && (
83 |
93 | )}
94 |
95 | Температура: {currentWeatherData?.main.temp.toFixed(1)}
96 |
97 |
98 |
99 | Oщущается как: {currentWeatherData?.main.feels_like.toFixed(1)}
100 |
101 | {currentWeatherData?.name}
102 |
103 |
104 |
105 |
106 |
107 | {currentWeatherData?.main.humidity}%
108 |
109 | Влажность
110 |
111 |
112 |
113 |
114 | {currentWeatherData?.wind.speed.toFixed(1)} км/ч
115 |
116 | Скорость ветра
117 |
118 |
119 |
124 |
125 | );
126 | }
127 |
128 | const styles = StyleSheet.create({
129 | container: {
130 | flex: 1,
131 | backgroundColor: "rgba(31,31,31,1)",
132 | alignItems: "center",
133 | justifyContent: "center",
134 | },
135 | weatherImagesSize: {
136 | width: 100,
137 | height: 100,
138 | },
139 |
140 | temp: {
141 | fontSize: 30,
142 | color: "#fff",
143 | fontWeight: "500",
144 | },
145 |
146 | feelslike: {
147 | fontSize: 15,
148 | color: "#fff",
149 | fontWeight: "400",
150 |
151 | marginTop: 7,
152 | },
153 |
154 | city: {
155 | fontSize: 20,
156 | color: "#fff",
157 |
158 | marginTop: 10,
159 | },
160 |
161 | dataContainer: {
162 | flexDirection: "row",
163 | gap: 30,
164 | },
165 |
166 | dataBlock: {
167 | alignItems: "center",
168 | justifyContent: "center",
169 |
170 | gap: 10,
171 |
172 | marginTop: 25,
173 | },
174 |
175 | dataSpeedHum: {
176 | fontSize: 17,
177 | color: "#fff",
178 | },
179 | });
180 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/assets/images/adaptive-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/weather-app/assets/images/adaptive-icon.png
--------------------------------------------------------------------------------
/mobile_apps/weather-app/assets/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/weather-app/assets/images/favicon.png
--------------------------------------------------------------------------------
/mobile_apps/weather-app/assets/images/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/weather-app/assets/images/icon.png
--------------------------------------------------------------------------------
/mobile_apps/weather-app/assets/images/splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/w3di/react-native-course/9dd1d58c887be243459494d9b6d074bd8100c228/mobile_apps/weather-app/assets/images/splash.png
--------------------------------------------------------------------------------
/mobile_apps/weather-app/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = function (api) {
2 | api.cache(true);
3 | return {
4 | presets: ['babel-preset-expo'],
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/components/SearchInput.tsx:
--------------------------------------------------------------------------------
1 | import {
2 | StyleSheet,
3 | Text,
4 | TouchableHighlight,
5 | ScrollView,
6 | TextInput,
7 | TouchableOpacity,
8 | View,
9 | } from "react-native";
10 | import { useState } from "react";
11 |
12 | import { useFetchCities } from "../hooks/useGetCities";
13 | import { AntDesign, MaterialCommunityIcons } from "@expo/vector-icons";
14 |
15 | export default function InputSearch({
16 | onChangeText,
17 | handleCurrentLocation,
18 | handleCityLocation,
19 | }: {
20 | onChangeText: (e: string) => void;
21 | handleCurrentLocation: () => void;
22 | handleCityLocation: () => void;
23 | }) {
24 | const [isSearchValueFocus, setIsSearchValueFocus] = useState(false);
25 |
26 | const [localValue, setLocalValue] = useState("");
27 |
28 | const {
29 | data: citiesData,
30 | isError: citiesisError,
31 | isLoading: citiesIsLoading,
32 | } = useFetchCities(localValue);
33 |
34 | return (
35 |
43 | setIsSearchValueFocus(true)}
48 | />
49 | {
58 | setIsSearchValueFocus(false);
59 | onChangeText(localValue);
60 | handleCityLocation();
61 | }}
62 | >
63 |
64 |
65 |
66 | {
75 | setIsSearchValueFocus(false);
76 | handleCurrentLocation();
77 | }}
78 | >
79 |
84 |
85 |
86 | {isSearchValueFocus && citiesData.length > 0 && (
87 |
99 | {citiesisError ? (
100 | Error
101 | ) : (
102 | citiesData.map((city, index) => (
103 | {
106 | onChangeText(city);
107 | setLocalValue(city);
108 | setIsSearchValueFocus(false);
109 | }}
110 | >
111 | {city}
112 |
113 | ))
114 | )}
115 |
116 | )}
117 |
118 | );
119 | }
120 |
121 | const styles = StyleSheet.create({});
122 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/eas.json:
--------------------------------------------------------------------------------
1 | {
2 | "cli": {
3 | "version": ">= 9.1.0"
4 | },
5 | "build": {
6 | "development": {
7 | "developmentClient": true,
8 | "distribution": "internal"
9 | },
10 | "preview": {
11 | "distribution": "internal"
12 | },
13 | "production": {}
14 | },
15 | "submit": {
16 | "production": {}
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/hooks/useCityWeather.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import axios from "axios";
3 | import { WeatherData } from "../types";
4 | import { API_KEY } from "../api/url";
5 |
6 | const useCityWeather = (city?: string) => {
7 | const [data, setData] = useState(null);
8 | const [isLoading, setIsLoading] = useState(true);
9 | const [isError, setIsError] = useState(false);
10 |
11 | useEffect(() => {
12 | const fetchWeather = async () => {
13 | setIsLoading(true);
14 | setIsError(false);
15 |
16 | try {
17 | const response = await axios.get(
18 | `https://api.openweathermap.org/data/2.5/weather`,
19 | {
20 | params: {
21 | units: "metric",
22 | lang: "ru",
23 | q: city,
24 | appid: API_KEY,
25 | },
26 | }
27 | );
28 |
29 | setData(response.data);
30 | } catch (error) {
31 | console.log("Ошибка в useCityWeather", error);
32 | setIsError(true);
33 | } finally {
34 | setIsLoading(false);
35 | }
36 | };
37 |
38 | fetchWeather();
39 | }, [city]);
40 |
41 | return { data, isLoading, isError };
42 | };
43 |
44 | export default useCityWeather;
45 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/hooks/useCurrentPositionWeather.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import axios from "axios";
3 | import { WeatherData } from "../types";
4 | import { API_KEY } from "../api/url";
5 |
6 | interface Coords {
7 | latitude?: number;
8 | longitude?: number;
9 | }
10 |
11 | const useCurrentPositionWeather = ({ latitude, longitude }: Coords) => {
12 | const [data, setData] = useState(null);
13 | const [isLoading, setIsLoading] = useState(false);
14 | const [isError, setIsError] = useState(false);
15 |
16 | useEffect(() => {
17 | if (latitude === undefined || longitude === undefined) return;
18 |
19 | const fetchWeather = async () => {
20 | setIsLoading(true);
21 | setIsError(false);
22 |
23 | try {
24 | const response = await axios.get(
25 | `https://api.openweathermap.org/data/2.5/weather`,
26 | {
27 | params: {
28 | units: "metric",
29 | lang: "ru",
30 | lat: latitude,
31 | lon: longitude,
32 | appid: API_KEY,
33 | },
34 | }
35 | );
36 |
37 | setData(response.data);
38 | } catch (error) {
39 | console.log("Error fetching weather data:", error);
40 | setIsError(true);
41 | } finally {
42 | setIsLoading(false);
43 | }
44 | };
45 |
46 | fetchWeather();
47 | }, [latitude, longitude]);
48 |
49 | return { data, isLoading, isError };
50 | };
51 |
52 | export default useCurrentPositionWeather;
53 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/hooks/useGetCities.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect, useCallback } from "react";
2 | import axios from "axios";
3 |
4 | const cache: { [key: string]: string[] } = {};
5 |
6 | export const useFetchCities = (city: string) => {
7 | const [data, setData] = useState([]);
8 | const [isLoading, setIsLoading] = useState(false);
9 | const [isError, setIsError] = useState(false);
10 |
11 | const controller = new AbortController();
12 |
13 | const fetchListOfCities = useCallback(async () => {
14 | if (cache[city]) {
15 | setData(cache[city]);
16 | return;
17 | }
18 |
19 | setIsLoading(true);
20 | setIsError(false);
21 |
22 | try {
23 | const response = await axios.get(
24 | `http://geodb-free-service.wirefreethought.com/v1/geo/places`,
25 | {
26 | signal: controller.signal,
27 | params: {
28 | namePrefix: city,
29 | hateoasMode: false,
30 | limit: 10,
31 | offset: 0,
32 | },
33 | }
34 | );
35 |
36 | const citiesArray: string[] = response.data.data.map(
37 | (obj: any) => obj.name
38 | );
39 |
40 | const uniqueCities = Array.from(new Set(citiesArray));
41 |
42 | cache[city] = uniqueCities;
43 | setData(uniqueCities);
44 | } catch (error) {
45 | if (!axios.isCancel(error)) {
46 | console.log("Ошибка при загрузке данных:", error);
47 | setIsError(true);
48 | }
49 | } finally {
50 | setIsLoading(false);
51 | }
52 | }, [city]);
53 |
54 | useEffect(() => {
55 | if (city.length < 2) {
56 | setData([]);
57 | return;
58 | }
59 |
60 | fetchListOfCities();
61 |
62 | return () => {
63 | controller.abort();
64 | };
65 | }, [fetchListOfCities, city]);
66 |
67 | return { data, isLoading, isError };
68 | };
69 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "weather-app",
3 | "main": "expo-router/entry",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "start": "expo start",
7 | "android": "expo start --android",
8 | "ios": "expo start --ios",
9 | "lint": "expo lint"
10 | },
11 | "jest": {
12 | "preset": "jest-expo"
13 | },
14 | "dependencies": {
15 | "@expo/vector-icons": "^14.0.2",
16 | "@react-navigation/native": "^6.0.2",
17 | "axios": "^1.7.7",
18 | "expo": "~51.0.28",
19 | "expo-linking": "~6.3.1",
20 | "expo-location": "~17.0.1",
21 | "expo-router": "~3.5.23",
22 | "expo-status-bar": "~1.12.1",
23 | "react": "18.2.0",
24 | "react-dom": "18.2.0",
25 | "react-native": "0.74.5",
26 | "react-native-safe-area-context": "4.10.5",
27 | "react-native-screens": "3.31.1"
28 | },
29 | "devDependencies": {
30 | "@babel/core": "^7.20.0",
31 | "@types/react": "~18.2.45",
32 | "typescript": "~5.3.3"
33 | },
34 | "private": true
35 | }
36 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "expo/tsconfig.base",
3 | "compilerOptions": {
4 | "strict": true,
5 | "paths": {
6 | "@base/*": ["./components/base/*"],
7 | "@widget/*": ["./components/widgets/*"],
8 | "@hooks/*": ["./helpers/hooks/*"],
9 | "@functions/*": ["./helpers/functions/*"],
10 | }
11 | },
12 | "include": [
13 | "**/*.ts",
14 | "**/*.tsx",
15 | ".expo/types/**/*.ts",
16 | "expo-env.d.ts"
17 | ]
18 | }
19 |
--------------------------------------------------------------------------------
/mobile_apps/weather-app/types.ts:
--------------------------------------------------------------------------------
1 | interface Coord {
2 | lon: number
3 | lat: number
4 | }
5 |
6 | interface Weather {
7 | id: number
8 | main: string
9 | description: string
10 | icon: string
11 | }
12 |
13 | interface Main {
14 | temp: number
15 | feels_like: number
16 | temp_min: number
17 | temp_max: number
18 | pressure: number
19 | humidity: number
20 | sea_level: number
21 | grnd_level: number
22 | }
23 |
24 | interface Wind {
25 | speed: number
26 | deg: number
27 | gust: number
28 | }
29 |
30 | interface Rain {
31 | '1h': number
32 | }
33 |
34 | interface Clouds {
35 | all: number
36 | }
37 |
38 | interface Sys {
39 | type: number
40 | id: number
41 | country: string
42 | sunrise: number
43 | sunset: number
44 | }
45 |
46 | export interface WeatherData {
47 | coord: Coord
48 | weather: Weather[]
49 | base: string
50 | main: Main
51 | visibility: number
52 | wind: Wind
53 | rain: Rain
54 | clouds: Clouds
55 | dt: number
56 | sys: Sys
57 | timezone: number
58 | id: number
59 | name: string
60 | cod: number
61 | }
62 |
--------------------------------------------------------------------------------