├── .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 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /mobile_apps/BMI_Calc/assets/images/plus.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 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 | --------------------------------------------------------------------------------