M3 | WebDev
103 subscribers
105 photos
4 videos
14 links
Your guide to the world of programming 🌐🚀
Download Telegram
🌟 Понимаем конструкцию `try...catch` и оператор `throw` в JavaScript 🌟

В JavaScript обработка ошибок выполняется с помощью конструкции try...catch и оператора throw. Давайте разберемся в деталях!

🔄 Конструкция try...catch

- Блок `try`: Здесь размещается код, в котором потенциально может возникнуть ошибка.
- Блок `catch`: Если в блоке try произошла ошибка, исполнение передается в блок catch. Здесь мы можем обработать ошибку и принять меры для продолжения работы приложения.

try {
// Код, который может вызвать ошибку
let data = JSON.parse('{"name": "John"}');
} catch (error) {
console.error("Ошибка: " + error.message);
}


💥 Оператор throw

Если необходимо намеренно создать ошибку, используется оператор throw. Это полезно, когда нужно остановить выполнение кода при возникновении определенных условий.

function divide(a, b) {
if (b === 0) {
throw new Error("Деление на ноль невозможно!");
}
return a / b;
}

try {
let result = divide(10, 0);
} catch (error) {
console.error("Произошла ошибка: " + error.message);
}


🛠 Объект Error

Когда возникает ошибка, создается объект Error, содержащий информацию об ошибке:
- `error.message`: Текст ошибки.
- `error.name`: Имя ошибки (например, TypeError, ReferenceError).
- `error.stack`: Стек вызовов, указывающий путь выполнения кода до места возникновения ошибки.

📚 Кастомные ошибки

Вы можете создать свои собственные ошибки, расширяя класс Error:

class CustomError extends Error {
constructor(message) {
super(message);
this.name = "CustomError";
}
}

try {
throw new CustomError("Это моя собственная ошибка!");
} catch (error) {
console.error(`${error.name}: ${error.message}`);
}


Когда использовать?

1. Валидация данных: Убедитесь, что передаваемые данные соответствуют ожиданиям.
2. Асинхронные операции: Обработайте ошибки, возникающие при работе с промисами или асинхронными вызовами.
3. Неожиданные состояния: Выявляйте и обрабатывайте состояния, которые не должны возникать в нормальных условиях.

🚀 Заключение

Использование try...catch, throw, и объекта Error помогает сделать код более надежным, предсказуемым и легким для отладки. Обработка ошибок — это залог создания стабильных приложений! 💻
🚀 Базовое Понимание и Возможности Классов в JavaScript

В JavaScript классы появились в ES6 и предоставляют новый способ работы с объектами, однако под капотом классы — это всё ещё функции. Классы упрощают создание объектов, наследование и использование методов, делая код более понятным и структурированным. Давайте рассмотрим основные аспекты работы с классами.

📚 Базовый синтаксис класса

Класс объявляется с использованием ключевого слова class, после которого следует имя класса. Внутри класса можно объявить методы. Например:

class User {
constructor(name) {
this.name = name;
}

sayHi() {
console.log(`Привет, я ${this.name}!`);
}
}

const user = new User('Иван');
user.sayHi(); // Привет, я Иван!

Здесь constructor — это специальный метод, который вызывается при создании нового объекта через new. Внутри конструктора определяются свойства объекта.

🧬 Наследование классов

В JavaScript классы поддерживают наследование. Для этого используется ключевое слово extends, которое позволяет одному классу наследовать методы и свойства другого.

class Animal {
constructor(name) {
this.name = name;
}

speak() {
console.log(`${this.name} издает звук.`);
}
}

class Dog extends Animal {
speak() {
console.log(`${this.name} лает.`);
}
}

const dog = new Dog('Барбос');
dog.speak(); // Барбос лает.

📊 Статические свойства и методы

Статические методы и свойства принадлежат классу, а не его экземплярам. Они определяются с помощью ключевого слова static.

class MathUtils {
static square(x) {
return x * x;
}
}

console.log(MathUtils.square(4)); // 16

🔒 Приватные и защищённые методы и свойства

С появлением ES2022 в JavaScript были введены приватные свойства и методы, которые начинаются с символа #. Такие свойства и методы доступны только внутри класса.

class User {
#password;

constructor(name, password) {
this.name = name;
this.#password = password;
}

checkPassword(password) {
return this.#password === password;
}
}

const user = new User('Иван', '1234');
console.log(user.checkPassword('1234')); // true

🔧 Расширение встроенных классов

Вы можете расширять встроенные классы JavaScript, такие как Array, добавляя собственные методы.

class PowerArray extends Array {
isEmpty() {
return this.length === 0;
}
}

const arr = new PowerArray(1, 2, 3);
console.log(arr.isEmpty()); // false

🔍 Проверка класса: "instanceof"

Оператор instanceof используется для проверки, принадлежит ли объект определённому классу или его наследнику.

console.log(arr instanceof PowerArray); // true

🧩 Примеси

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

let sayHiMixin = {
sayHi() {
console.log(`Привет, ${this.name}`);
}
};

class User {
constructor(name) {
this.name = name;
}
}

Object.assign(User.prototype, sayHiMixin);

const user = new User('Иван');
user.sayHi(); // Привет, Иван

🧭 Заключение:

Классы в JavaScript делают код более чистым и позволяют легко создавать сложные архитектуры, оставаясь при этом гибкими и мощными. Используйте их, чтобы создавать иерархии объектов, организовывать повторно используемые компоненты и улучшать читаемость кода.

Тэги : #javascript
🎉 Что будет выведено а консоль?
Anonymous Quiz
47%
Hello!, Hello!
27%
Hello!, TypeError
20%
TypeError, Hello
7%
Ошибка
🚀 Базовые Принципы ООП

Классы в JavaScript предоставляют мощные инструменты для организации и структурирования кода, используя ключевые принципы объектно-ориентированного программирования (ООП). Давайте разберём основные из них.

🛡 Инкапсуляция

Инкапсуляция заключается в скрытии внутренней реализации объекта, предоставляя только необходимый интерфейс для взаимодействия с ним. Это позволяет защитить данные и поддерживать код в чистоте.

Пример был показан в предыдущим посту .

🧬 Наследование

Наследование позволяет одному классу (подклассу) унаследовать свойства и методы другого класса (родительского), расширяя и переопределяя их при необходимости. Это помогает избегать дублирования кода.

Пример был показан в предыдущим посту .

🎭 Полиморфизм

Полиморфизм позволяет методам, с одинаковыми именами в разных классах, работать по-разному в зависимости от объекта. Это позволяет создавать более гибкие и расширяемые структуры.

Пример:

class Animal {
speak() {
console.log('Животное издает звук.');
}
}

class Dog extends Animal {
speak() {
console.log('Собака лает.');
}
}

class Cat extends Animal {
speak() {
console.log('Кошка мяукает.');
}
}

const animals = [new Dog(), new Cat()];
animals.forEach(animal => animal.speak());
// Собака лает.
// Кошка мяукает.

🔗 Внедрение зависимостей (Dependency Injection)

Внедрение зависимостей — это паттерн, который позволяет передавать зависимости (например, объекты или службы) в конструктор класса, что делает классы более гибкими и тестируемыми.

Пример:

class Engine {
start() {
console.log('Двигатель запущен');
}
}

class Car {
constructor(engine) {
this.engine = engine;
}

drive() {
this.engine.start();
console.log('Машина едет');
}
}

const engine = new Engine();
const car = new Car(engine);
car.drive();
// Двигатель запущен
// Машина едет

🧩 Абстракция

Абстракция
— это принцип ООП, который позволяет выделить только важные детали и скрыть сложные внутренние механизмы.

class CoffeeMachine {
makeCoffee() {
this.#boilWater();
this.#brewCoffee();
this.#pourInCup();
console.log('Coffee is ready!');
}

#boilWater() {
console.log('Boiling water...');
}

#brewCoffee() {
console.log('Brewing coffee...');
}

#pourInCup() {
console.log('Pouring coffee into cup...');
}
}

const myCoffeeMachine = new CoffeeMachine();
myCoffeeMachine.makeCoffee();

📄 Интерфейсы (в контексте TypeScript)

Хотя в чистом JavaScript интерфейсы отсутствуют, в TypeScript они позволяют определять структуру объектов, задавая обязательные методы и свойства для классов, которые их реализуют.

Пример:

interface Drivable {
drive(): void;
}

class Car implements Drivable {
drive() {
console.log('Машина едет');
}
}

const car = new Car();
car.drive(); // Машина едет

🧭 Заключение:

📢 Эти принципы помогают создавать мощные и гибкие архитектуры, которые легко поддерживать и расширять. Начните использовать их в своём коде, и вы почувствуете, как он становится более структурированным и понятным! А следующий пост будет про приципы SOLID 🚀

Тэги : #javascript
🔥 SOLID Принципы в JavaScript 🚀

SOLID — это набор из пяти принципов, которые помогают писать понятный, поддерживаемый и расширяемый код в объектно-ориентированном программировании (ООП). Давайте разберём каждый принцип с примерами на JavaScript!


1️⃣ Single Responsibility Principle (SRP) — Принцип единственной ответственности

Каждый класс должен иметь одну ответственность.

class User {
constructor(name) {
this.name = name;
}
}

class UserRepository {
save(user) {
// Сохраняет пользователя в БД
}
}

Здесь User отвечает за данные пользователя, а UserRepository — за сохранение данных. 📝


2️⃣ Open/Closed Principle (OCP) — Принцип открытости/закрытости

Классы должны быть открыты для расширения, но закрыты для изменения. Например, добавляем новые фигуры, не меняя существующий код:

class Shape {
area() {
throw 'Метод должен быть реализован';
}
}

class Circle extends Shape {
constructor(radius) {
super();
this.radius = radius;
}

area() {
return Math.PI * this.radius * this.radius;
}
}

Вы можете добавить новый класс Square, не меняя код Circle или Shape. ⭕️🔲


3️⃣ Liskov Substitution Principle (LSP) — Принцип подстановки Барбары Лисков

Подклассы должны заменять базовые классы без ошибок. Это означает, что любой экземпляр подкласса должен быть возможной заменой экземпляра родительского класса.

class Rectangle {
constructor(width, height) {
this.width = width;
this.height = height;
}

area() {
return this.width * this.height;
}
}

class Square extends Rectangle {
constructor(side) {
super(side, side);
}
}

Экземпляр Square может заменить Rectangle и будет работать корректно. 🟦➡️🟥

4️⃣ Interface Segregation Principle (ISP) — Принцип разделения интерфейса

Лучше много маленьких интерфейсов, чем один большой. Пример на TS :

interface Printer {
print(doc: string): void;
}

interface Scanner {
scan(): string;
}

class MultiFunctionDevice implements Printer, Scanner {
print(doc: string) {
console.log(`Печать документа: ${doc}`);
}

scan() {
return 'Документ отсканирован';
}
}

💡 Реализуйте только необходимые интерфейсы.


5️⃣ Dependency Inversion Principle (DIP) — Принцип инверсии зависимостей

Высокоуровневые модули не зависят от низкоуровневых, оба зависят от абстракций.

class MySQLConnection {
connect() {
console.log('Подключение к MySQL');
}
}

class MongoDBConnection {
connect() {
console.log('Подключение к MongoDB');
}
}

class UserRepository {
constructor(dbConnection) {
this.dbConnection = dbConnection;
}

connect() {
this.dbConnection.connect();
}
}

const userRepository = new UserRepository(new MySQLConnection());
userRepository.connect();

Здесь UserRepository зависит от абстракции подключения к БД, а не от конкретной реализации, что упрощает замену БД. 🛠


⚙️ Применение SOLID принципов помогает создавать гибкие и поддерживаемые приложения! Используйте их, чтобы ваш код стал прочным, как камень! 💪🔥

Тэги : #javascript
💡 Всё о Web-хранилищах: `localStorage`, `sessionStorage` и `Cookies`

Веб-хранилища в JavaScript помогают сохранять данные прямо в браузере пользователя. Разберём, что из них чем отличается и где используется.

1️⃣ localStorage

- 💾 Хранение: Данные сохраняются без ограничения по времени. Даже после закрытия браузера данные останутся.
- 📦 Вместимость: Обычно около 5-10 МБ на домен.
- 📌 Применение: Подходит для хранения пользовательских настроек, корзины покупок и других данных, которые нужно сохранять между сессиями.

2️⃣ sessionStorage

- Хранение: Данные сохраняются только на время сессии. Закроете вкладку — данные исчезнут.
- 📦 Вместимость: Аналогично localStorage, но тоже около 5-10 МБ.
- 📌 Применение: Используется для временных данных, которые нужны только на время работы с одной вкладкой, например, для состояния UI или промежуточных данных форм.

3️⃣ Cookies

- 🍪 Хранение: Данные хранятся до указанного времени истечения или пока не будут удалены. Могут передаваться на сервер при каждом запросе.
- 📦 Вместимость: Обычно до 4 КБ.
- 🔒 Заголовки: Настройки безопасности и срока действия задаются с помощью заголовков Set-Cookie и атрибутов Secure, HttpOnly, SameSite.
- 📌 Применение: Идеальны для авторизации, хранения сессий пользователя и других данных, которые должны передаваться между клиентом и сервером.

🛠 Когда и что использовать?
- `localStorage` — для данных, которые нужно сохранять на долгий срок.
- `sessionStorage` — для данных, которые нужны на время сессии.
- `Cookies` — для данных, которые должны передаваться между клиентом и сервером.

💻 Пример использования:

javascript
// localStorage
// Сохранение данных
localStorage.setItem('username', 'John');

// Получение данных
const user = localStorage.getItem('username');
console.log(user); // 'John'

// Удаление данных
localStorage.removeItem('username');

// Очистка всего хранилища
localStorage.clear();

// sessionStorage
// Сохранение данных на время сессии
sessionStorage.setItem('sessionID', '12345');

// Получение данных
const session = sessionStorage.getItem('sessionID');
console.log(session); // '12345'

// Удаление данных
sessionStorage.removeItem('sessionID');

// Очистка всего сессионного хранилища
sessionStorage.clear();

// Cookies
// Создание куки
document.cookie = "theme=dark; max-age=3600; path=/";

// Получение всех куки
console.log(document.cookie); // 'theme=dark'

// Удаление куки
document.cookie = "theme=; max-age=0; path=/";

Заключение: Правильный выбор веб-хранилища помогает улучшить производительность и удобство использования веб-приложений. 🚀
🎯 Какой тип веб-хранилища передаётся на сервер с каждым HTTP-запросом? 🎯
Anonymous Quiz
8%
localStorage
0%
sessionStorage
85%
Cookies
8%
Все перечисленные
📜 Свойства объекта в JavaScript и их конфигурация

Свойства объектов в JavaScript не ограничиваются только значениями. Они обладают флагами и могут быть геттерами/сеттерами. Давайте разберемся, как это работает.

🔍 Флаги и дескрипторы свойств

Когда создается объект, его свойства имеют три базовых флага:

1. writable: Если true, значение свойства можно изменять.
2. enumerable: Если true, свойство участвует в перечислении через циклы (for...in) или методы (Object.keys).
3. configurable: Если true, свойство можно удалить, а также изменять его флаги.

Флаги задаются при помощи дескрипторов. По умолчанию все флаги имеют значение true.

🛠 Пример использования флагов

const car = { brand: "Toyota" };

Object.defineProperty(car, 'brand', {
writable: false,
enumerable: false,
configurable: false
});

// Теперь свойства "brand" не будет видно в циклах и его нельзя изменить или удалить.
console.log(car.brand); // Toyota
car.brand = "Honda"; // Ошибка: свойство недоступно для изменения


Для получения дескрипторов свойств используется Object.getOwnPropertyDescriptor:

let descriptor = Object.getOwnPropertyDescriptor(car, 'brand');
console.log(descriptor);
// Вывод: { value: 'Toyota', writable: false, enumerable: false, configurable: false }


🛠 Свойства — геттеры и сеттеры

Геттеры и сеттеры позволяют управлять доступом к свойствам объектов, добавляя дополнительные проверки, вычисления или логику.

- Геттер (get): возвращает значение при обращении к свойству.
- Сеттер (set): вызывается при установке значения свойства.

🛠 Пример геттеров и сеттеров

const person = {
firstName: 'Alice',
lastName: 'Johnson',

get fullName() {
return `${this.firstName} ${this.lastName}`;
},

set fullName(value) {
[this.firstName, this.lastName] = value.split(' ');
}
};

console.log(person.fullName); // Alice Johnson
person.fullName = 'John Doe';
console.log(person.firstName); // John
console.log(person.lastName); // Doe


В этом примере, при присвоении person.fullName у нас автоматически устанавливаются firstName и lastName.

📋 Практические случаи применения:

1. Контроль доступа: Изменение writable позволяет защитить важные данные от случайных изменений.
2. Настраиваемое поведение: Использование геттеров и сеттеров упрощает работу с данными, добавляя возможность валидации или форматирования.
3. Оптимизация производительности: Отключение enumerable для некоторых свойств помогает скрыть их в циклах или при копировании объектов.

📊 Сводка: В чем преимущества?

- 📌 Безопасность данных: Защита свойств от изменений или удаления.
- 📌 Гибкость: Настраиваемое поведение при чтении и записи.
- 📌 Удобство работы с объектами: Легкость реализации вычисляемых свойств и контроля за доступом.

Изучение свойств и их конфигурации поможет глубже понять JavaScript и писать более чистый и защищенный код! 🎉

Тэги : #javascript
Что будет выведено в консоль ?
Anonymous Quiz
13%
Alex
50%
Ошибка TypeError
13%
Bo
25%
undefined
Пост про связанные списки 📚

Связанный список — это абстрактная структура данных, позволяющая вставлять элементы в любую точку памяти за O(1) (константное время). Чтение элементов занимает O(n), где *n* — количество элементов в списке.

🧩 Основные компоненты связанного списка:

1. Узел (Node): Содержит значение и ссылку на следующий узел.
2. Заголовок (Head): Указывает на начало списка.
3. Хвост (Tail): Ссылка на последний узел, который ссылается на null.

Двухнаправленный связанный список:

Имеет ссылки как на следующий, так и на предыдущий узлы, что облегчает навигацию в обе стороны.

📊 Сравнение массивов и связанных списков:

1. Хранение данных:

- Массив: Элементы массива хранятся в памяти последовательно, непрерывно. Это означает, что доступ к элементам массива по индексу осуществляется за константное время.

- Связанный список: Элементы связанного списка хранятся в разных участках памяти, связанных указателями. Для доступа к элементам требуется последовательно пройти по указателям от начала списка до нужного элемента, что делает доступ по индексу менее эффективным.

2. Размер и изменяемость:

- Массив: Размер массива фиксирован и определяется при создании. Изменение размера массива может потребовать перевыделения памяти и копирования элементов.

- Связанный список: Размер связанного списка может динамически меняться, поскольку элементы не обязательно должны быть хранены последовательно в памяти.

3. Вставка и удаление элементов:

- Массив: Вставка и удаление элементов из середины массива требует перемещения всех элементов после изменяемого, что может быть затратно по времени.

- Связанный список: Вставка и удаление элементов из середины списка требует только перенаправления указателей, что делает эти операции более эффективными.

4. Память:

- Массив: Массивы могут потреблять больше памяти, чем реально требуется, особенно если размер массива больше, чем количество используемых элементов.

- Связанный список: Связанные списки могут быть более эффективны в использовании памяти, поскольку они выделяют память только для фактически используемых элементов.

5. Сложность операций:

- Массив: В среднем доступ к элементу массива по индексу имеет сложность O(1), а вставка и удаление элементов в середине массива имеют сложность O(n), где n - размер массива.

- Связанный список: Доступ к элементу по индексу имеет сложность O(n), а вставка и удаление элементов в середине списка имеют сложность O(1).

Пример реализации на JavaScript:

class Node {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
}

class LinkedList {
constructor() {
this.head = null;
this.tail = null;
}

append(value) {
const newNode = new Node(value);

if (!this.head || !this.tail) {
this.head = newNode;
this.tail = newNode;
return this;
}

this.tail.next = newNode;
this.tail = newNode;
return this;
}

prepend(value) {
const newNode = new Node(value, this.head);
this.head = newNode;

if (!this.tail) {
this.tail = newNode;
}
return this;
}

find(value) {
if (!this.head) return null;
let current = this.head;

while (current) {
if (current.value === value) return current;
current = current.next;
}
return null;
}

insertAfter(value, prevNode) {
if (prevNode === null) return this;
const newNode = new Node(value);
newNode.next = prevNode.next;
prevNode.next = newNode;

if (newNode.next === null) this.tail = newNode;
return this;
}
}

🎯 Где используются связанные списки?

- Связанные списки используются в реализациях различных алгоритмов и структур данных , когда важно избежать перевыделения памяти.

Тэги : #javascript #структурыданных