progway — программирование, IT
2.68K subscribers
25 photos
1 video
246 links
Чат: @prog_way_chat

Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT

Полезности и навигация в закрепе

По всем вопросам: @denisputnov
Download Telegram
Реализация мемоизации в JavaScript

О том, что такое мемоизация, я рассказывал в прошлом посте.

На самом деле, всё это довольно просто. Попробуем написать функцию-обёртку memoize, с помощью которой можно мемоизировать любую другую функцию. Начнём как всегда с интерфейса:

function memoize(func) {
// ...
}


Наша функция-обёртка будет принимать только целевую функцию, которую мы хотим мемоизировать. В качестве кэша будем использовать Map:

const cache = new Map();


И далее просто воспользуемся замыканием, чтобы ограничить доступ к созданному кэшу только для целевой функции. Для этого вернем из memoize новую функцию:

return function(...args) {
// ключ сериализуем в строку, чтобы
// не было проблем с аргументами
// объектами, массивами и т.д.
const key = JSON.stringify(args);

// проверяем есть ли результат в кэше
if (!cache.has(key)) {
// если нет, то сохраняем в кэш
// значение вызова функции
cache.set(key, func(...args));
}

// и возвращаем значение из кэша
return cache.get(key);
};


Полный код функции:


function memoize(func) {
const cache = new Map();

return function(...args) {
const key = JSON.stringify(args);

if (!cache.has(key)) {
cache.set(key, func(...args));
}

return cache.get(key);
};
}


Я осознанно не использовал TypeScript, так как он сильно визуально усложняет эту функцию и объяснений получается много. Натыкайте 🔥 на пост и я разберу как правильно типизировать такую функцию

@prog_way_blogчат#theory #code #javascript #data
🔥76👍5🐳21😁1
const car = {
size: 'small'
};

const box = {
type: 'mailbox',
small: true
};


@prog_way_blogчат#quiz
👍5🐳2
При выполнении какого кода будет ошибка? И будет ли?
Anonymous Quiz
47%
box.car.size
11%
box[car.size]
12%
box[car["size"]]
31%
Ошибки не будет
🔥12🤯12🐳2👍1
Как типизировать функцию мемоизации

В прошлом посте я разбирал реализацию функции мемоизации на JavaScript и упомянул, что типов там нет осознанно. В этом посте мы отдельно разберём типизацию такой функции, это будет полный разбор для самых маленьких.

Шпаргалка по используемым в посте utility-типам:

Parameters<T> - возвращает тип аргументов функции T
ReturnType<T> - возвращает тип возвращаемых значений функции T

const foo = (a: number , b: number) => 5

type Args = Parameters<typeof foo>
// [a: number, b: number]

type Return = ReturnType<typeof foo>
// number


Итак, наша функция принимает в себя другую функцию. Сразу же типизируем это:

function memoize(func: (...args: any[]) => any) {
// ...
}


Далее было бы неплохо типизировать возвращаемую функцию. Для этого мы можем использовать следующую конструкцию: (...args: Parameters<оригинальная функция>) => ReturnType<оригинальная функция>. И вот мы сталкиваемся с проблемой, что для корректной типизации возвращаемой функции нам необходимы типы Parameters и ReturnType, которые обязательно принимают дженерик. В качестве дженерика выступает тип оригинальной функции. Для удобства вынесем тип оригинальной функции в дженерик функции memoize:

function memoize<T extends (...args: any[]) => any>(func: T) {
// ...
}


И итоговый интерфейс функции у нас сильно растянется, но будет таким:

type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>

function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
// ...
}


Ребята, стараюсь максимально упростить. Если плохо понимаете дженерики, постарайтесь более внимательно вчитываться в код.

Далее типизация кэша, тут всё просто:

const cache = new Map<string, ReturnType<T>>();


По типизации, ключ — строка, а значение — тот тип, который возвращает оригинальная функция.

Далее рассмотрим итоговый код:

type AnyFunction = (...args: any[]) => any;
type MemoizedFunction<T extends AnyFunction> =
(...args: Parameters<T>) => ReturnType<T>

function memoize<T extends AnyFunction>(func: T): MemoizedFunction {
const cache = new Map<string, ReturnType<T>>();

return function(...args: Parameters<T>): ReturnType<T> {
const key = JSON.stringify(args);

if (!cache.has(key)) {
cache.set(key, func(...args));
}

return cache.get(key)!;
};
}


Надеюсь вышло понятно. Если что, любые вопросы можем обсудить в комментариях.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#code #typescript
🔥24👍6🤯32🐳1
Обработка сочетания клавиш в JavaScript

Чтобы обработать сочетание клавиш, необходимо подписаться на событие keydown. В большинстве случаев вы будете подписываться на document, если сочетание клавиш глобальное по всему приложению.

Для примера возьмём сложное сочетание клавиш: command(alt) + shift + U

document.addEventListener('keydown', function(event) {
if (event.metaKey && event.shiftKey && event.key === 'U') {
// че-то делаем на нажатие
}
});


Но тут стоит учитывать, что metaKey в разных браузерах работает по разному, в том числе могут быть проблемы в Safari. Самым безопасным вариантом будет следующий код:

document.addEventListener('keydown', function(event) {
const isApple = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);

if ((isApple && event.metaKey && event.shiftKey && event.key === 'U') ||
(!isApple && event.altKey && event.shiftKey && event.key === 'U')) {
// че-то делаем на нажатие
}
});


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#theory #code #javascript
👍4710🤯4🔥3🐳3🌚2
Не забывайте про реакции 🌚
Please open Telegram to view this post
VIEW IN TELEGRAM
🐳13🔥10🌚9🍌95👍2👀2🎄2
Что такое структурная типизация

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

У нас есть два типа Fireman и Programmer, а также функция, принимающая объект типа Fireman:

type Fireman = {
name: string
}

type Programmer = {
name: string
}

const fireman: Fireman = {
name: "Alex"
}

const programmer: Programmer = {
name: "Denis"
}

const foo = (person: Fireman) => { ... }


Номинальная типизация:

foo(fireman) // OK
foo(programmer) // Error


Но почему во втором случае ошибка? Потому что разные типы: функция ожидает на вход Fireman, а получает Programmer. Сравнение происходит только по самому типу.

А вот пример со структурной типизацией:

foo(fireman) // OK
foo(programmer) // OK


В этом случае всё отработает корректно, но только потому что Programmer и Fireman абсолютно идентичны по своей структуре.

Также будет работать и в случае, если один из типов будет являться подмножеством другого:

type Fireman = {
name: string;
}

type Programmer = {
name: string;
age: number
}

const fireman: Fireman = ...
const programmer: Programmer = ...

const foo = (person: Fireman) => { ... }

foo(fireman) // OK
foo(programmer) // OK


Даже тут ошибки нет, а всё потому что тип Fireman полностью включен в тип Programmer и при вызове функции объект типа Programmer полностью удовлетворяет типу ожидаемой структуры, а следовательно и ошибки не будет. Для языка не важно, что у Programmer есть какие-то дополнительные поля. Главное, чтобы присутствовали все из типа Fireman и имели такой же тип.

В этом и заключается весь смысл структурной типизации.

Спасибо за прочтение, это важно для меня ❤️

#web #theory #typescript
21👍5🔥5🐳1
let a = { name: 'progway' };
let b;

b = a;
a.name = 'denis';
console.log(b.name);


@prog_way_blogчат#quiz
🐳51
Что будет в консоли?
Anonymous Quiz
20%
progway
72%
denis
5%
undefined
2%
ReferenceError
🙏9🐳7🤷‍♂11
В чем заключается разница между интерфейсом и типом?

Для меня большое удивление, что я до сих пор не смог найти нормального материала, где был бы описан этот вопрос. В этом после я планирую исправить эту несправедливость.

Тип — обозначается ключевым словом type — представляет собой либо описание структуры (объекта, функции…), либо набор других типов или структур:

// набор типов
type Identifier = string | boolean;

// описание структуры
type Person = {
name: string;
age: number;
}

// набор типов или структур
type Foo = Person | string;


Интерфейс — обозначается ключевым словом inderface — может описывать только структуры:

interface Props {
title: string;
visible?: boolean;
}


Особенности типов:
1. Только типами можно создать типы-объединения (они же union type):

type Identifier = string | number
type Animal = Dog | Cat


2. Только типами можно создавать кортежи, фиксируя тип элемента массива по индексу и длину массива:

type Cortage = [string, number, boolean]


3. Только с помощью типов можно создавать псевдонимы (они же alias):

type Name = string
type Author = Name


4. Типами проще и красивее создавать описание функций:

type Foo = (a: string) => number

interface Foo {
(a: string): number
}


Особенности интерфейсов:
1. Только интерфейсы имеют перегрузку типов:

interface Person {
name: string
}

interface Person {
age: number
}

const kate: Person = {
name: "Екатерина",
age: 24
}


2. Только интерфейсы могут быть имплементированы:

interface Person {}

class Fireman implements Person {}


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

Спасибо за прочтение, это важно для меня ❤️

#web #theory #typescript
👍48🔥87🐳2
Сужение типов и уточняющие тайпгарды

Часто в TypeScript коде можно столкнуться с тем, что типы недостаточно точны. Это бывает в случаях, когда мы определяем типы, например, через unionstring | number и других подобных случаях. Рассмотрим пример:

const value: string | number = ...

parseInt(value) // ошибка


В таком случае мы получим TypeError , а всё потому что переменная value имеет более общий тип, чем тот, что ожидает parseInt — эта функция ожидает первым аргументом на вход только строку. В таком случае нам может помочь сужение типов, которое нам дают дополнительные проверки — тайпгарды.

Тайпгарды — Type Guards — это языковые конструкции, проверки, которые позволяют определить или уточнить тип переменной средствами JavaScript. Тайпгарды бывают двух видов — уточняющие и определяющие.

Уточняющие тайпгарды — проверки, которые позволяют вывести более узкий тип из общего типа, например вывести string из типа string | number | boolean | null.

Определяющие же тайпгарды — проверки, которые позволяют вывести узкий тип из неизвестного типа, который в идеальном мире обозначается типом unknown

Есть несколько способов сузить тип:

1. Через оператор typeof

const value: string | number = ...

if (typeof value === 'string') {
// ошибки не будет, т.к.
// тип value в этом условии
// строго равняется "string"
parseInt(value)
}


2. Через ключевое слово in или метод hasOwnProperty

const value: any[] | number = ...

if ("map" in value) {
// value === array
value.map(...)
}

const animal = Cat | Dog = ...

if (animal.hasOwnProperty('meow')) {
// animal === Cat
animal.meow()
}


3. Через ключевое слово instanceof

const person: Fireman | Programmer = ...

// при условии что Programmer - класс
// а person - инстанс класса
if (person instanceof Programmer) {
person.code()
}


4. Через встроенные в язык функции проверки типа

const value: any[] | number = ...

if (Array.isArray(value)) {
value.map(...)
}


5. Через existed check, например, для null и undefined

const user: User | null = ...

if (user) {
console.log(user.name)
}


Также подобные проверки можно выносить в отдельные функции, которые обычно именуются по следующему шаблону — is + <название типа или интерфейса> , например, для типа User будет логично создать тайпгард isUser, вот небольшой пример:

type Account = User | Admin | Manager

const isUser = (account: Account): account is User => {
return account.type === "user"
}


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

В нашем контексте, предикат — уникальное определяющее свойство сущности, относительно которого можно быть точно уверенным в её идентичности.

Если более просто, то мы знаем, что если account.type === “user” , то перед нами ни что иное как User. В этом случае тип аккаунта является предикатом, на основе которого можно делать выводы о типе аккаунта без дополнительных проверок.

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

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#theory #code #typescript
🔥20👍127🐳2🎄1
let x = 5;
let y = new Number(5);
let z = 5;

console.log(x == y);
console.log(x === y);
console.log(y === z);


@prog_way_blogчат#quiz
🐳6🗿4🔥3😎1
Что такое Fullscreen API

Fullscreen API — это интерфейс для работы с полноэкранным режимом в веб-браузерах, который позволяет элементам HTML-страницы разворачиваться на весь экран.

Яркий пример использования Fullscreen API — это видеоплееры. Когда вы нажимаете кнопку для просмотра видео на весь экран, используется именно этот API. Но его возможности далеко не ограничиваются видео: он может быть применен к любым элементам страницы, будь то изображения, модалки и любые другие блоки страницы.

Пример использования следующий:

// получаем элемент, который хотим открыть на весь экран
const element = document.getElementById('target');

// открыть элемент на весь экран
element.requestFullscreen()

// получить элемент, который открыть в полноэкранном режиме
document.fullscreenElement

// выйти из полноэкранного режима
document.exitFullsreen()


Также методы requestFullscreen и exitFullscreen являются промисами, что позволяет проще работать с ними и обрабатывать ошибки их вызова.

И ещё важно знать, что из полноэкранного режима можно выйти по нажатию клавиши ESC по умолчанию, а также некоторые браузеры дают собственные сочетания клавиш. Чтобы обработать и такой случай, можно отслеживать отдельное событие:

document.addEventListener('fullscreenchange', () => {
// как-то обрабатываем изменение состояния

// можно завязаться на
// document.fullscreenElement
})


Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#theory #code #javascript #web #useful
👍16🔥11🐳54
let progway;
progwya = {};
console.log(progway);


@prog_way_blogчат#quiz
🗿12🐳2
🐳11🤬5🤓4👍1
Псевдоселекторы в CSS

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

Псевдоселекторы бывают двух видов:
1. Псевдоклассы — применяются к элементам на основе их состояния или взаимодействия с пользователем
2. Псевдоэлементы — позволяют стилизовать определённые части элементов

Примеры псевдоклассов:

1. :hover — применяется, когда пользователь наводит указатель мыши на элемент

a:hover {
color: red;
}


В этом примере цвет текста ссылки изменится на красный при наведении курсора

2. :nth-child(n) — выбирает элементы на основе их позиции среди братьев и сестёр

li:nth-child(2) {
background-color: yellow;
}


Здесь каждый второй элемент списка li будет иметь жёлтый фон

3. :focus — применяется к элементу, когда он получает фокус (например, при клике или переходе по табуляции)

input:focus {
border-color: blue;
}


В этом примере цвет рамки текстового поля станет синим, когда элемент получит фокус

Конечно же, это не все псевдоклассы, которые существуют в CSS. В этом посте рассмотрим только часть для примера

Примеры псевдоэлементов:

1. ::before — вставляет содержимое перед элементом

p::before {
content: "Note: ";
font-weight: bold;
}


Этот стиль добавит текст "Note: " перед каждым параграфом p

2. ::after — вставляет содержимое после элемента.

p::after {
content: " ->";
color: grey;
}


В этом примере текст "->" будет добавлен после каждого параграфа

Ну и также не стоит забывать о том, что все псевдоселекторы можно сочетать, если правила стилизации у нас более сложные:

li:nth-child(odd):hover {
background-color: lightblue;
}


Этот код изменит цвет фона каждого нечётного элемента списка на светло-голубой при наведении на него курсора.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#theory #web #useful
👍306🔥4🐳1
Что такое семантика?

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

Семантических тегов множество, однако, самые используемые из них:

<header> - заголовок секции или документа
<nav> - навигационное меню
<article> - независимая часть контента, например, статья, пост...
<section> - определяет раздел конкретного документа, статьи, поста...
<aside> - содержит контент, связанный с основным содержанием страницы, но не являющийся его частью
<footer> - представляет нижний колонтитул секции или документа


Конечно же семантических тегов сильно больше, но рассматривать их все в этом посте я не буду.

Важнее сказать, что семантические теги делятся на 2 категории значимости:
— Первая категория, по сути, имеет те же свойства и вид, что обычный div. Их особенность заключается лишь в том, как эти теги будут обрабатываться парсерами и служат они в основном для SEO.
— Вторая категория — когда тег имеет дополнительные уникальные свойства и поведение, а, возможно, и внешний вид.

Давайте сразу на примере:

<header> - по сути, тот же <div>, но просто парсится иначе

<button> - тоже семантический тег

Но, помимо особой семантической значимости, этот тег также имеет и другие свойства:
- встроенные обработчики событий для взаимодействия с клавиатуры
- иной внешний вид
- верная HTML-роль по умолчанию


На самом деле, семантический тег — это всё, что не <div>. Только этот тег не имеет особого назначения и нужен лишь для группировки других тегов. Остальные же теги несут в себе какой-то дополнительный семантический смысл.

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

Да и в целом не забывайте про реакции. Они реально мотивируют меня что-то писать.

Спасибо за прочтение, это важно для меня ❤️

@prog_way_blogчат#theory #web #useful
🔥69👍8🐳6