Геттеры и сеттеры
Геттеры и сеттеры в JavaScript — это методы, которые позволяют вам контролировать доступ к свойствам объекта. Они используются для получения (геттеры) и установки (сеттеры) значений свойств объекта. Геттеры и сеттеры предоставляют возможность добавлять дополнительную логику при доступе к свойствам, например, для валидации данных или преобразования значений.
📌 Геттеры (Getters)
Геттер — это метод, который вызывается при обращении к свойству объекта. Он позволяет вам вычислить и вернуть значение свойства вместо того, чтобы просто его хранить.
📌 Сеттеры (Setters)
Сеттер — это метод, который вызывается при попытке установить значение свойства. Он позволяет вам контролировать, какие значения могут быть присвоены свойству, и выполнять дополнительные действия при присвоении.
📌 Применение
Геттеры и сеттеры часто используются, когда необходимо:
✔️ Добавить логику в момент чтения или записи свойства.
✔️ Контролировать доступ к приватным данным.
✔️ Создать свойства, значение которых вычисляется на основе других данных.
✔️ Обеспечить валидацию данных при установке значений.
#frontend #javascript
Геттеры и сеттеры в JavaScript — это методы, которые позволяют вам контролировать доступ к свойствам объекта. Они используются для получения (геттеры) и установки (сеттеры) значений свойств объекта. Геттеры и сеттеры предоставляют возможность добавлять дополнительную логику при доступе к свойствам, например, для валидации данных или преобразования значений.
Геттер — это метод, который вызывается при обращении к свойству объекта. Он позволяет вам вычислить и вернуть значение свойства вместо того, чтобы просто его хранить.
const person = {
firstName: 'John',
get fullName() {
return `${this.firstName}`;
}
};
console.log(person.fullName); // "John"
Сеттер — это метод, который вызывается при попытке установить значение свойства. Он позволяет вам контролировать, какие значения могут быть присвоены свойству, и выполнять дополнительные действия при присвоении.
const person = {
firstName: 'John',
lastName: 'Doe',
set fullName(name) {
const [first, last] = name.split(' ');
this.firstName = first;
this.lastName = last;
}
};
person.fullName = 'Jane Smith';
console.log(person.firstName); // "Jane"
console.log(person.lastName); // "Smith"
Геттеры и сеттеры часто используются, когда необходимо:
#frontend #javascript
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥2💯1
Проблема изменения вложенных объектов при использовании map
При использовании метода map для создания нового массива объектов, возникает проблема, если объекты содержат вложенные объекты. Хотя map возвращает новый массив, вложенные объекты внутри элементов массива остаются ссылками на те же объекты, что и в оригинальном массиве.
⚠️ Что происходит:
- В исходном массиве persons есть объект с вложенным объектом address.
- Метод map создает новый массив newPersons, в котором каждый элемент копируется с использованием оператора расширения {...person}.
- Однако, несмотря на создание нового объекта верхнего уровня, вложенный объект address в обоих массивах (persons и newPersons) ссылается на один и тот же объект.
📌 Результат
Изменения, внесенные в newPersons, также повлияют на оригинальный массив persons, так как вложенные объекты не были скопированы глубоко.
✔️ Решение
Чтобы избежать этого, нужно использовать глубокое копирование вложенных объектов, например, с использованием JSON.parse(JSON.stringify(person)) или библиотек, которые поддерживают глубокое копирование.
В реальных проектах стараются избегать необходимости глубокого клонирования на каждом шаге. Вместо этого можем частично склонировать
#frontend #javascript
При использовании метода map для создания нового массива объектов, возникает проблема, если объекты содержат вложенные объекты. Хотя map возвращает новый массив, вложенные объекты внутри элементов массива остаются ссылками на те же объекты, что и в оригинальном массиве.
const persons = [{
name: 'Ivan',
address: {
ul: 1
}
}]
const newPersons = persons.map(person => {
person.address.ul = 2
return {...person}
})
console.log(persons)
console.log(newPersons)
- В исходном массиве persons есть объект с вложенным объектом address.
- Метод map создает новый массив newPersons, в котором каждый элемент копируется с использованием оператора расширения {...person}.
- Однако, несмотря на создание нового объекта верхнего уровня, вложенный объект address в обоих массивах (persons и newPersons) ссылается на один и тот же объект.
Изменения, внесенные в newPersons, также повлияют на оригинальный массив persons, так как вложенные объекты не были скопированы глубоко.
Чтобы избежать этого, нужно использовать глубокое копирование вложенных объектов, например, с использованием JSON.parse(JSON.stringify(person)) или библиотек, которые поддерживают глубокое копирование.
В реальных проектах стараются избегать необходимости глубокого клонирования на каждом шаге. Вместо этого можем частично склонировать
const newPersons = persons.map(person => {
return {
...person,
address: { ...person.address, ul: 2 }
}
})
#frontend #javascript
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🔥3💯1
Типы и структуры данных
Типы данных и структуры данных часто путают, но это две разные концепции, которые играют важную роль в программировании.
📌 Типы данных — это категории, в которые классифицируются данные. Они определяют, какие операции можно выполнять с этими данными и как они хранятся в памяти. В JavaScript есть примитивные и ссылочные типы данных:
📌 Структуры данных — это способы организации и хранения данных в памяти таким образом, чтобы к ним было удобно обращаться и эффективно работать. В JavaScript структуры данных включают:
❓ В чем разница?
Типы данных — это отдельные значения (например, число или строка), тогда как структуры данных — это контейнеры, организующие и хранящие эти значения для более сложных операций (например, массив или объект).
Тип данных определяет, что это за значение, а структура данных — как эти значения организованы.
#frontend #javascript
👍 Менторство | 🔝 Сообщество
Типы данных и структуры данных часто путают, но это две разные концепции, которые играют важную роль в программировании.
Примитивные типы данных: Number, String, Boolean, Null, Undefined, Symbol, BigInt.
Ссылочные типы данных: Object (включая массивы, функции и даты).
Массивы (Array): Упорядоченные списки элементов, доступ к которым осуществляется по индексу.
Объекты (Object): Коллекции пар "ключ-значение", где ключи — это строки (или символы), а значения могут быть любыми типами данных.
Наборы (Set): Коллекции уникальных значений, где каждое значение может появляться только один раз.
Карты (Map): Коллекции пар "ключ-значение", где ключи могут быть любого типа, не только строками.
Типы данных — это отдельные значения (например, число или строка), тогда как структуры данных — это контейнеры, организующие и хранящие эти значения для более сложных операций (например, массив или объект).
Тип данных определяет, что это за значение, а структура данных — как эти значения организованы.
#frontend #javascript
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥3💯1
Сравнение объектов и Map в JavaScript
📌 Тип ключей:
Объект: Ключи приводятся к строкам. Любой нестроковый ключ, например объект, будет преобразован в строку.
Map: Ключи могут быть любого типа, включая объекты, функции и числа.
📌 Порядок ключей:
Объект: Порядок ключей не гарантирован.
Map: Порядок ключей сохраняется в том порядке, в котором они были добавлены.
📌 Итерация:
Объект: Нужно использовать Object.keys(), Object.values(), или Object.entries() для итерации.
Map: Поддерживает методы для итерации по умолчанию, включая map.keys(), map.values(), и map.entries().
📌 Дополнительные методы:
Объект: Ограниченные возможности, требует использования Object.keys(), Object.values(), и других вспомогательных функций для работы с данными. Для очистки свойств нужно явно удалять каждое свойство.
Map: Обладает множеством удобных методов:
set(key, value): Добавляет элемент.
get(key): Получает значение по ключу.
has(key): Проверяет наличие ключа.
delete(key): Удаляет элемент.
clear(): Удаляет все элементы.
#frontend #javascript #map #object
Объект: Ключи приводятся к строкам. Любой нестроковый ключ, например объект, будет преобразован в строку.
Map: Ключи могут быть любого типа, включая объекты, функции и числа.
const obj = {};
const map = new Map();
const keyObj = {};
obj[keyObj] = 'value'; // Ключ преобразуется в "[object Object]"
map.set(keyObj, 'value'); // Ключ остается объектом
console.log(obj[keyObj]); // 'value'
console.log(map.get(keyObj)); // 'value'
Объект: Порядок ключей не гарантирован.
Map: Порядок ключей сохраняется в том порядке, в котором они были добавлены.
const obj = { b: 2, a: 1 };
const map = new Map([['b', 2], ['a', 1]]);
console.log(Object.keys(obj)); // ['b', 'a'] (порядок не гарантирован)
console.log([...map.keys()]); // ['b', 'a'] (порядок гарантирован)
Объект: Нужно использовать Object.keys(), Object.values(), или Object.entries() для итерации.
Map: Поддерживает методы для итерации по умолчанию, включая map.keys(), map.values(), и map.entries().
const obj = { a: 1, b: 2 };
const map = new Map([['a', 1], ['b', 2]]);
for (const key in obj) {
console.log(key, obj[key]);
}
for (const [key, value] of map) {
console.log(key, value);
}
Объект: Ограниченные возможности, требует использования Object.keys(), Object.values(), и других вспомогательных функций для работы с данными. Для очистки свойств нужно явно удалять каждое свойство.
Map: Обладает множеством удобных методов:
set(key, value): Добавляет элемент.
get(key): Получает значение по ключу.
has(key): Проверяет наличие ключа.
delete(key): Удаляет элемент.
clear(): Удаляет все элементы.
#frontend #javascript #map #object
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍16💯2🔥1
Event loop: Как запомнить микро- и макротаски
❗️ Микротаски всегда выполняются сразу после текущей операции и всегда до следующей макротаски.
⚡️ Микротаски имеют приоритет. Как только появляется микротаска, она всегда выполняется первой.
⚡️ Макротаски — крупные задачи, такие как setTimeout, setInterval, выполнение основного кода скрипта и обработка событий. Они выполняются по очереди из своей очереди, но только после выполнения всех микротасок.
⚡️ Когда выполняется макротаска, и в процессе возникают микротаски (например, через Promise), все микротаски должны быть выполнены до того, как начнется следующая макротаска.
#frontend #javascript #eventloop
Микротаски:
- Promise: Все колбеки, добавленные с помощью then, catch, finally.
- process.nextTick: В Node.js используется для выполнения задачи до следующего прохода в цикле событий.
- MutationObserver: Колбеки, которые срабатывают при изменении DOM.
Макротаски:
- setTimeout и setInterval: Асинхронные вызовы с задержкой.
- setImmediate: (в Node.js) Вызовы, которые выполняются на следующей итерации цикла событий, после текущей макротаски.
- I/O задачи: Например, операции ввода/вывода (запросы к сети, чтение файлов).
- UI Rendering: Обновления пользовательского интерфейса (в браузере).
- Основной код скрипта: Тот код, который запускается в начале выполнения программы.
#frontend #javascript #eventloop
Please open Telegram to view this post
VIEW IN TELEGRAM
👍25💯4🤝2
Чем отличаются циклы for...in и for...of в JavaScript
Цикл for...in используется для перебора свойств объекта (ключей), а также всех индексов массива, если он используется с массивом. Это важно: for...in перебирает ключи (индексы массива), а не значения.
Пример с объектом:
Пример с массивом:
Цикл for...of используется для перебора значений итерируемых объектов, таких как массивы, строки, Map, Set и т.д. Он перебирает значения.
Пример с массивом:
Пример со строкой:
❓ Как запомнить
Используйте for...in для обхода ключей объектов или индексов массива. Используйте for...of для обхода значений массивов, строк или других итерируемых объектов.
#frontend #javascript
for...inЦикл for...in используется для перебора свойств объекта (ключей), а также всех индексов массива, если он используется с массивом. Это важно: for...in перебирает ключи (индексы массива), а не значения.
Пример с объектом:
const car = {
make: 'Toyota',
model: 'Corolla',
year: 2020
};
for (const key in car) {
console.log(key, car[key]);
}
// make Toyota
// model Corolla
// year 2020
Пример с массивом:
const fruits = ['apple', 'banana', 'cherry'];
for (const index in fruits) {
console.log(index, fruits[index]);
}
// 0 apple
// 1 banana
// 2 cherry
for...ofЦикл for...of используется для перебора значений итерируемых объектов, таких как массивы, строки, Map, Set и т.д. Он перебирает значения.
Пример с массивом:
const fruits = ['apple', 'banana', 'cherry'];
for (const fruit of fruits) {
console.log(fruit);
}
// apple
// banana
// cherry
Пример со строкой:
const name = 'Alice';
for (const char of name) {
console.log(char);
}
// A
// l
// i
// c
// e
for...in – для индексов и свойств объекта.for...of – для объектов итерируемых, значений.Используйте for...in для обхода ключей объектов или индексов массива. Используйте for...of для обхода значений массивов, строк или других итерируемых объектов.
#frontend #javascript
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥26👍11❤3🤝1
Когда приложение разрастается, работа с состоянием через обычные глобальные переменные становится непрактичной и приводит к хаосу. Чтобы избежать этого, важно использовать более структурированные подходы, такие как паттерн Observer. Он помогает разделить логику обновления и реакцию на изменения, что делает код более гибким и легко масштабируемым.
Рассмотрим, как создать и использовать простую реализацию этого паттерна для управления состоянием.
В отдельном файле создадим функцию, которая будет хранить состояние и управлять подписчиками. Назовем её createObservable:
// observable.js
export const createObservable = (initialState = []) => {
let state = initialState;
let observers = [];
// Метод для уведомления всех подписчиков об изменениях
const notify = () => {
observers.forEach((observer) => observer(state));
};
return {
// Метод для подписки на изменения
subscribe: (observer) => {
observers = [...observers, observer];
},
// Метод для отмены подписки
unsubscribe: (observer) => {
observers = observers.filter((obs) => obs !== observer);
},
// Метод для изменения состояния и уведомления подписчиков
setState: (newState) => {
state = newState;
notify();
},
// Метод для получения текущего состояния
getState: () => state,
};
};
Теперь вместо использования обычного массива, создадим состояние для списка фильмов, используя наш createObservable. Это позволит нам централизованно управлять состоянием и уведомлять подписчиков об изменениях.
// store.js
import { createObservable } from './observable';
const moviesObservable = createObservable([]);
Теперь предположим, что вы загружаете данные о фильмах с API:
const fetchMovies = async (query) => {
const response = await fetch(`https://api.example.com/movies?search=${query}`);
const movies = await response.json();
return movies;
};
// Получаем фильмы и обновляем состояние хранилища
const moviesFromApi = await fetchMovies('Inception');
moviesObservable.setState(moviesFromApi); // Теперь в хранилище у нас массив фильмов
Когда состояние изменится, нам нужно автоматически отобразить новые данные. Например, создадим функцию displayMovies, которая будет выводить фильмы на экран, и подпишем её на наш moviesObservable:
const displayMovies = (movies) => {
console.log('Фильмы обновились:', movies);
};
// Подписываемся на изменения в состоянии хранилища
moviesObservable.subscribe(displayMovies);
Теперь каждый раз, когда состояние хранилища изменяется через setState, функция displayMovies будет автоматически вызываться с обновлёнными данными.
Для доступа к текущим данным из хранилища можно использовать метод getState:
const currentMovies = moviesObservable.getState();
console.log('Текущие фильмы:', currentMovies);
Преимущества использования паттерна Observer:
- Централизованное управление состоянием — вся логика управления данными сосредоточена в одном месте.
- Гибкость — вы можете легко добавлять новые подписки или отменять их при необходимости.
- Простота тестирования — можно отдельно тестировать логику хранилища и взаимодействие с подписчиками.
- Отделение состояния от представления — подписчики отвечают только за реакцию на изменения, а само хранилище не зависит от реализации компонентов интерфейса.
Этот паттерн можно легко расширить на более сложные состояния: добавить возможность частичного обновления состояния, реализовать логику редукторов для обновления состояния в зависимости от действий, подключить несколько таких хранилищ и организовать обмен данными между ними.
Использование паттерна Observer — это хорошая база для перехода к более сложным инструментам управления состоянием, таким как Redux или MobX.
#javascript #store #observer
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤3🔥3
Разница между паттерном Адаптер и Маппер
Адаптер и Маппер — это два подхода, часто используемых для работы с несовместимыми интерфейсами или для преобразования данных между системами. Хотя они могут казаться похожими, их цели и применение немного отличаются.
➕ Адаптер (Adapter Pattern)
Паттерн Адаптер позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли посредника, переводя один интерфейс в другой. Основное предназначение — это сделать два интерфейса совместимыми, не изменяя существующий код.
➕ Маппер (Mapper)
Маппер (или преобразователь) используется для преобразования данных из одного формата в другой. В отличие от адаптера, который сосредоточен на интерфейсах, маппер преобразует сами данные.
❓ Когда использовать:
💭 Для меня Адаптер — это способ адаптировать данные и методы, чтобы разные системы или компоненты могли работать вместе.
Маппер — это инструмент для преобразования данных в определённый формат. Например, если у нас есть разные сущности, но мы хотим сделать общий дропдаун, маппер преобразует данные так, чтобы они подходили для этого дропдауна. Это позволяет избежать дублирования кода.
#frontend #javascript #patterns
Адаптер и Маппер — это два подхода, часто используемых для работы с несовместимыми интерфейсами или для преобразования данных между системами. Хотя они могут казаться похожими, их цели и применение немного отличаются.
Паттерн Адаптер позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли посредника, переводя один интерфейс в другой. Основное предназначение — это сделать два интерфейса совместимыми, не изменяя существующий код.
Маппер (или преобразователь) используется для преобразования данных из одного формата в другой. В отличие от адаптера, который сосредоточен на интерфейсах, маппер преобразует сами данные.
Адаптер - когда у вас есть два класса или интерфейса, которые должны работать вместе, но у них разные интерфейсы.
Маппер - когда вам нужно изменить структуру или формат данных для дальнейшей обработки.
Маппер — это инструмент для преобразования данных в определённый формат. Например, если у нас есть разные сущности, но мы хотим сделать общий дропдаун, маппер преобразует данные так, чтобы они подходили для этого дропдауна. Это позволяет избежать дублирования кода.
#frontend #javascript #patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15🔥7💯2
Она позволяет задавать шаблон для объектов, чтобы каждый новый объект, созданный через этот конструктор, имел определенные свойства и методы. Давайте разберем, как работает функция-конструктор.
Функция-конструктор выглядит как обычная функция, но она пишется с заглавной буквы по соглашению, чтобы отличаться от других функций. Внутри конструктора используется this для задания свойств создаваемого объекта.
function Person(name, age) {
this.name = name; // свойство name
this.age = age; // свойство age
}
Чтобы создать объект с помощью конструктора, используется оператор new. Он:
- Создает новый пустой объект.
- Связывает его с this внутри конструктора.
- Возвращает этот объект.
const person1 = new Person("Alice", 25);
console.log(person1.name); // Alice
console.log(person1.age); // 25
Если мы добавим метод прямо в конструктор, то он будет копироваться в каждый новый объект, что может тратить память.
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHello = function() {
console.log(`Hi, I'm ${this.name}`);
};
}
const person1 = new Person("Alice", 25);
person1.sayHello(); // Hi, I'm Alice
Для методов можно использовать prototype, чтобы метод существовал в одном экземпляре и не копировался для каждого объекта.
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log(`Hi, I'm ${this.name}`);
};
const person1 = new Person("Alice", 25);
const person2 = new Person("Bob", 30);
person1.sayHello(); // Hi, I'm Alice
person2.sayHello(); // Hi, I'm Bob
В функции-конструкторе this указывает на новый объект, который создается при вызове через new. Это позволяет настраивать свойства и методы нового объекта.
- Наследование. Используя прототипы, можно создавать наследуемые свойства и методы.
- Проверка с instanceof. Для проверки, создан ли объект через конструктор, можно использовать instanceof.
console.log(person1 instanceof Person); // true
#javascript #this #function
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18🔥5💯1
Mutation Observer — это интерфейс, позволяющий отслеживать изменения в DOM, такие как добавление или удаление элементов, изменение атрибутов или текста. Он предоставляет более эффективный способ наблюдать за изменениями, чем старые методы вроде Mutation Events, так как не блокирует поток выполнения и может отслеживать сразу несколько изменений.
Mutation Observer полезен, если нужно:
- отслеживать изменения в структуре DOM (например, добавление или удаление элементов);
- реагировать на изменения атрибутов элементов;
- мониторить текстовое содержимое элементов, например, для динамически обновляемых данных.
Создание Mutation Observer
Создать Mutation Observer можно с помощью конструктора
MutationObserver, в который передается колбэк-функция. Эта функция будет вызываться с массивом записей (`MutationRecord`), описывающих изменения.
const observer = new MutationObserver((mutationsList) => {
mutationsList.forEach((mutation) => {
console.log(mutation);
});
});
Каждый объект `mutation` в `mutationsList` содержит информацию о произошедшем изменении, включая:
- `type` — тип изменения (`childList`, `attributes`, или `characterData`);
- `target` — целевой элемент, где произошло изменение;
- `addedNodes` и `removedNodes` — список добавленных или удаленных узлов, если `type` — `childList`;
- `attributeName` — имя измененного атрибута, если `type` — `attributes`.
Начало наблюдения
Чтобы начать наблюдение, нужно использовать метод
observe и указать целевой элемент и параметры наблюдения.
const targetNode = document.getElementById('targetElement');
observer.observe(targetNode, {
childList: true, // следить за добавлением и удалением дочерних элементов
attributes: true, // следить за изменением атрибутов
characterData: true, // следить за изменением текстового содержимого
subtree: true // отслеживать изменения во всех потомках
});
Остановка наблюдения
Когда больше не нужно отслеживать изменения, можно остановить наблюдение с помощью метода
disconnect():
observer.disconnect();
Полезные параметры конфигурации
- `childList`: отслеживает добавление и удаление дочерних элементов.
- `attributes`: отслеживает изменения атрибутов у целевого элемента.
- `characterData`: отслеживает изменения текстового содержимого.
- `subtree`: если установлено в `true`, позволяет отслеживать изменения не только у целевого элемента, но и у всех его потомков.
#javascript #observer
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍5❤2