This media is not supported in your browser
VIEW IN TELEGRAM
Бинарный поиск
Сегодня поговорим о бинарном поиске.
Бинарный поиск нужен для того, чтобы быстро что-то найти. Для того, чтобы можно было легко что-то найти, нужен порядок (прямо как в шкафу). Проще говоря, данные, где вы ищите, должны быть отсортированы по какому-нибудь признаку.
Алгоритм бинарного поиска заключается в том, что мы делим кучу данных на две равные кучки данных поменьше и затем пытаемся понять, какая из двух кучек нам подходит. После того, как мы это поняли, мы продолжаем поиск в нужной кучке. Вот и весь Великий и Ужасный Алгоритм, которым пугают джунов, как бабайкой.С вас три тыщи.
В классическом варианте вы наверняка увидите массив чисел, в котором ищется числовластвуй сравнивай” - очень полезная.
В повседневной работе идея делить кучу на две поменьше пригождается в самых разных ситуациях. Например, конструкция
Можно пойти дальше в своих размышлениях и додумать до идеи делить кучу не на две, а на три. Такие задачи иногда дают младшеклассникам на олимпиадах по математике. Мне впервые попалась такая в подготовительных материалах, когда мне было 8 лет, и решение дошло до меня только на следующий день.
Удачных вам разделений и сравнений!
#алгосы
Сегодня поговорим о бинарном поиске.
Бинарный поиск нужен для того, чтобы быстро что-то найти. Для того, чтобы можно было легко что-то найти, нужен порядок (прямо как в шкафу). Проще говоря, данные, где вы ищите, должны быть отсортированы по какому-нибудь признаку.
Алгоритм бинарного поиска заключается в том, что мы делим кучу данных на две равные кучки данных поменьше и затем пытаемся понять, какая из двух кучек нам подходит. После того, как мы это поняли, мы продолжаем поиск в нужной кучке. Вот и весь Великий и Ужасный Алгоритм, которым пугают джунов, как бабайкой.
В классическом варианте вы наверняка увидите массив чисел, в котором ищется число
x, равное, ну скажем для примера, 17. Мы делим кучку на две части пополам, и смотрим, чему равна середина. Если середина больше 17, то нам нужно искать в левой кучке (там, где числа поменьше). Если середина меньше 17, то наша кучка - правая. Искать таким образом числа в массиве вам, скорее всего, не потребуется никогда, но вот сама идея - “разделяй и В повседневной работе идея делить кучу на две поменьше пригождается в самых разных ситуациях. Например, конструкция
if else тоже позволяет поделить данные на две кучки по какому-нибудь признаку. А еще та идея полезна для дебага. Допустим, вы внесли много изменений в код и в какой-то момент все сломалось (прямо как у меня сегодня). Как быстро найти проблемный файл? Очень просто: убираем половину ченжей (например, в stash) и проверяем, как это отразилось на баге. Если баг все еще воспроизводится, то делим эту кучку еще на две. Эту же идею использует для дебага git bisect. Можно пойти дальше в своих размышлениях и додумать до идеи делить кучу не на две, а на три. Такие задачи иногда дают младшеклассникам на олимпиадах по математике. Мне впервые попалась такая в подготовительных материалах, когда мне было 8 лет, и решение дошло до меня только на следующий день.
Удачных вам разделений и сравнений!
#алгосы
1❤10👍7🥱4🔥3
Абстракция - это упрощение объекта до его ключевых характеристик. Благодаря абстракции мы можем пользоваться объектом, не вдаваясь в детали его реализации. Несмотря на кажущуюся сложность этого определения, абстракция нужна, чтобы облегчить нам жизнь. Абстракция заставляет объекты и функции соблюдать контракт (т.е. интерфейс), благодаря чему мы можем пользоваться ими, не разбираясь, как они этот контракт реализуют.
Работу абстракции можно сравнить с работой сеньора-программиста. Если вы даете задачу сеньору, то (упрощенно говоря) вас не волнует, каким именно образом он ее реализует, какие технологии выберет и какую архитектуру. Вы специально наняли сеньора, чтобы он решил все эти проблемы и избавил вас от головняка. То же самое с абстракциями: если у меня есть, скажем, функция, которая называется
sendRequest, я ожидаю, что она будет отправлять запросы, а уж как она это делает, меня не волнует.Работа абстракций во многом похожа на работу программистов. Во-первых, она должна делать то, что от нее ожидается (иначе это плохая абстракция, ее надо
Чтобы создать хорошую абстракцию, необходимо:
И да, сходство работает и в обратную сторону: пока программист делает то, что от него ожидается, мало кто интересуется, как именно он это делает 🙂
#ооп
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍7🥱7🔥2
Если вы понимаете, что такое рекурсия и когда её применять — можете пропускать этот пост 🙂
Рекурсия во фронтенде встречается чаще, чем кажется. Например:
Не всем программистам очевидно, когда именно стоит применять рекурсию. И здесь нам приходит на помощь понимание, что такое абстракция, о котором я писала в предыдущем посте. Абстракция даёт нам контракт, которым мы можем пользоваться, при этом нам не нужно знать ни детали реализации, ни даже быть уверенным в том, что эта реализация уже готова. То есть: при написании любой функции мы можем использовать ее саму, потому что ее контракт гарантирован.
Допустим, вы пишете функцию, которая вычисляет факториал - произведение всех чисел от
x до 1. Поможет ли результат этой же функции с каким-нибудь другим аргументом? Да - ведь нам надо вычислить произведение x на произведение всех предыдущих чисел, а это как раз факториал предыдущего числа x - 1. Значит, мы можем легко вычислить факториал следующим образом:const factorial = (x) => x * factorial(x - 1)
Затем нужно учесть корнер кейсы. Мы вычитаем 1 из
x и очевидно, что лучше не делать это до минус бесконечности. Нужно выбрать какое-то конкретное число, на котором мы остановимся. Логично выбрать число 0, потому что это наименьшее число, для которого определена функция факториала. Получаем финальное решение: const factorial = (x) => x ? x * factorial(x - 1) : 1
Задача: есть дерево, где каждая нода содержит id и массив children. Нужно собрать все id.
Заметим, что задача сильно упрощается, если нам не нужно думать про
id дочерних элементов. Предположим, что уже существует функция getChildrenIds, которая возвращает id дочерних элементов. Останется добавить id текущей ноды. Получаем решение:const getIds(node) => […getChildrenIds(), node.id]
Теперь реализуем
getChildrenIds. Она должна вернуть все id дочерних элементов. Но у нас уже есть функция getIds, которая вернет id элементов поддерева. Если вызвать ее для каждого потомка, то она вернет все id всех поддеревьев. Итого:const getIds = (node) => {
let result = [node.id];
node.children.forEach((child) => result = result.concat(getIds(child)))
return result;
}Желаю вам удачного выхода из рекурсивного цикла! 🔄 Еще про рекурсию можно почитать в этом посте.
#алгосы
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Фронтенд кухня🥘
🎯Рекурсия
Если вы понимаете, что такое рекурсия и когда её применять — можете пропускать этот пост 🙂
〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️
Рекурсия во фронтенде встречается чаще, чем кажется. Например:
🔘 вычисление коэффициентов…
Если вы понимаете, что такое рекурсия и когда её применять — можете пропускать этот пост 🙂
〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️〰️
Рекурсия во фронтенде встречается чаще, чем кажется. Например:
🔘 вычисление коэффициентов…
🔥8🥱5
Forwarded from fedos dot com
…
За последние десятилетия программисты видели массу инструментов, которые предположительно должны были устранить необходимость программирования. Сначала это были языки третьего поколения, потом — четвертого. Потом — автоматическое программирование. Потом — CASE-средства. Потом — визуальное программирование. Каждое из этих достижений привносило значительные улучшения, и общими усилиями они сделали программирование абсолютно неузнаваемым для тех, кто изучал его до этих нововведений. Но ни одна из этих инноваций не устранила программирования как такового.
Причина в том, что программирование — принципиально сложный процесс даже при наличии хорошего инструментария. Дело не в инструментах — программистам приходится бороться с несовершенством реального мира; нам нужно досконально продумывать последовательности, зависимости и исключения, иметь дело с конечными пользователями, которые никак не могут ничего решить. Нам всегда придется бороться с плохо определенными интерфейсами с другими программными и аппаратными средствам и всегда принимать во внимание инструкции, бизнес-правила и другие источники сложных проблем, возникающие вне мира программирования.
Нам всегда будут нужны люди, способные заполнить брешь между задачей реального мира, которую нужно решить, и компьютером, предназначенным для решения этой задачи. Эти люди будут называться программистами независимо от того, манипулируют они машинными регистрами на ассемблере или диалоговыми окнами в Microsoft Visual Basic. Пока у нас есть компьютеры, нам будут нужны люди, которые говорят компьютерам, чтó делать, и эта деятельность будет называться программированием.
Когда вы слышите заявления о том, что «новый инструментарий устранит необходимость компьютерного программирования», бегите! Или хотя бы посмейтесь про себя над этим наивным оптимизмом.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7💯3❤1👎1🤔1
Решила проверить, как обстоят дела с поиском работы для фронтендеров на hh. Создала максимально дефолтное резюме максимально дефолтного миддла на React, указала 3 года опыта работы в ноу нейм компания. Сделала 30 откликов (на большее не хватило времени).
Результаты:
▫️ Отказов: 10 (один автоматический спустя минуту, в бигтех)
▫️ Предложений от hr перейти общаться в телеграмм: 2
▫️ Тестовое: 1
▫️ Звонок (на hh появились звонки?...): 1
Что лично я считаю неплохим результатом.
Результаты:
Что лично я считаю неплохим результатом.
Please open Telegram to view this post
VIEW IN TELEGRAM
1🤗14💩8👍6✍1🤡1
🚀 Как делать задачи быстрее
Самый простой способ ускорить работу, если вы фронтенд-разработчик - это использовать жоский typenoscript. То есть не ограничиваться стандартными типами
Например,
📌 Чем жестче ваш typenoscript, тем быстрее вы будете работать.
На первый взгляд это звучит парадоксально: почему скорость работы увеличится, если жесткая типизация добавит работы? А вот почему:
1️⃣ Меньше ручных проверок
Большинство из нас пишет код так: написал, сохранил, перезагрузил браузер, проверил, поправил. Больше всего времени тратится на пересборку приложения, перезагрузку браузера и прохождение юзер флоу. Когда типы заданы строго, достаточно убедиться, что код скомпилировался. Проверить всю работу новой фичи можно один раз в самом конце, перед ревью.
(Это, конечно, работает, когда вы пишете логику, а не верстаете.)
2️⃣ Меньше багов и возвратов из тестирования
Основная задача typenoscript как инструмента - снизить количество ошибок в рантайме, перенеся их в compile-time. Чем жестче ваша типизация, тем меньше багов будет в результате🔜 меньше доработок и возвратов фичи из тестирования
3️⃣ Типы выполняют роль документации и делают код более читаемым.
Для тех, кто хочет попрактиковаться в написании типов, есть классный репозиторий https://github.com/type-challenges/type-challenges - в нем собраны задачи от самого легкого до продвинутого уровня.
Самый простой способ ускорить работу, если вы фронтенд-разработчик - это использовать жоский typenoscript. То есть не ограничиваться стандартными типами
string/number/boolean и объектами из них, а реально ограничить тип только возможными значениями. Например,
email - это не любой string, а только составленный по определенному правилу, содержащий символы @ и .. Пин-код, - это тоже не любой string, а строка ровно из 4 цифр.На первый взгляд это звучит парадоксально: почему скорость работы увеличится, если жесткая типизация добавит работы? А вот почему:
Большинство из нас пишет код так: написал, сохранил, перезагрузил браузер, проверил, поправил. Больше всего времени тратится на пересборку приложения, перезагрузку браузера и прохождение юзер флоу. Когда типы заданы строго, достаточно убедиться, что код скомпилировался. Проверить всю работу новой фичи можно один раз в самом конце, перед ревью.
(Это, конечно, работает, когда вы пишете логику, а не верстаете.)
Основная задача typenoscript как инструмента - снизить количество ошибок в рантайме, перенеся их в compile-time. Чем жестче ваша типизация, тем меньше багов будет в результате
Для тех, кто хочет попрактиковаться в написании типов, есть классный репозиторий https://github.com/type-challenges/type-challenges - в нем собраны задачи от самого легкого до продвинутого уровня.
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - type-challenges/type-challenges: Collection of TypeScript type challenges with online judge
Collection of TypeScript type challenges with online judge - type-challenges/type-challenges
1❤18🔥9👍4👎3❤🔥2🌚2✍1💯1🤝1
Дискуссия про применимость алгоритмических задач с собеседований в реальной работе получила новый виток. Сегодня в комментариях подкинули вот такую задачу с собеседования:
*️⃣ *️⃣ *️⃣
Вы хотите набрать строку s, состоящую из строчных латинских букв, в вашем любимом текстовом редакторе Notepad#.
Notepad# поддерживает два типа операций:
дописать любую букву в конец строки;
скопировать непрерывную подстроку уже напечатанной строки и вставить эту подстроку в конец строки.
Можно ли набрать строку s за число операций, меньшее длины строки?
canBeTypedFaster("tbank") => false
canBeTypedFaster("mama") => true
*️⃣ *️⃣ *️⃣
Задача несложная, мне потребовалось примерно двадцать секунд на подумать и еще пару минут на закодить. Вот что у меня получилось:
Как я рассуждала: для того, чтобы воспользоваться опцией копипаста, нужно, чтобы в целевой строке повторялась хотя бы одна группа из двух символов. Тогда эту группу можно будет скопировать и вставить. Можно и больше, но двух символов хватит. Следовательно, задача сводится к тому, чтобы понять, есть ли в строке повторяющиеся группы из двух элементов. Дальше все просто: я прохожусь по строке и запоминаю все группы из двух подряд идущих символов, а также проверяю, встречалась ли мне такая группа раньше. Если встречалась, то значит, эту группу можно скопировать и для такой строки ответ будет true. В противном случае ответ будет false.
Обратите внимание, для решения этой задачи мне не потребовались никакие Ужасные Алгоритмы вроде бинарного поиска, обхода дерева или хотя бы рекурсии. Вот, что я использовала:
🟣 Логическую редукцию: свела задачу поиска строк, которые можно набрать быстрее, к поиску строк, у которых есть группа из двух повторяющихся элементов.
🟣 Логическую дедукцию: свела задачу поиска повторяющихся групп к перебору всех возможных групп и сохнанению встреченных групп.
🟣 Логический синтез: собрала все вместе.
Именно навык рассуждать логически и проверяют на собеседованиях подобные задачи. Для того, чтобы решать такие задачи, необязательно задротить литкод (хотя это хорошая идея), достаточно научиться рассуждать логически. У меня на литкоде дайбох если штук 10 решенных задач есть, однако на собеседованиях я решаю 90% задач. Литкод - это не цель и не поэма, которую нужно выучить наизусть, это всего лишь тренажер для отработки навыков логического мышления.
#алгоритмы
Вы хотите набрать строку s, состоящую из строчных латинских букв, в вашем любимом текстовом редакторе Notepad#.
Notepad# поддерживает два типа операций:
дописать любую букву в конец строки;
скопировать непрерывную подстроку уже напечатанной строки и вставить эту подстроку в конец строки.
Можно ли набрать строку s за число операций, меньшее длины строки?
canBeTypedFaster("tbank") => false
canBeTypedFaster("mama") => true
Задача несложная, мне потребовалось примерно двадцать секунд на подумать и еще пару минут на закодить. Вот что у меня получилось:
function canBeTypedFaster(str) {
const set = new Set();
for (let i = 0; i < str.length - 1; i++) {
const substring = str.substring(i, i + 2);
if (set.has(substring)) {
return true;
}
set.add(substring);
}
return false;
}Как я рассуждала: для того, чтобы воспользоваться опцией копипаста, нужно, чтобы в целевой строке повторялась хотя бы одна группа из двух символов. Тогда эту группу можно будет скопировать и вставить. Можно и больше, но двух символов хватит. Следовательно, задача сводится к тому, чтобы понять, есть ли в строке повторяющиеся группы из двух элементов. Дальше все просто: я прохожусь по строке и запоминаю все группы из двух подряд идущих символов, а также проверяю, встречалась ли мне такая группа раньше. Если встречалась, то значит, эту группу можно скопировать и для такой строки ответ будет true. В противном случае ответ будет false.
Обратите внимание, для решения этой задачи мне не потребовались никакие Ужасные Алгоритмы вроде бинарного поиска, обхода дерева или хотя бы рекурсии. Вот, что я использовала:
Именно навык рассуждать логически и проверяют на собеседованиях подобные задачи. Для того, чтобы решать такие задачи, необязательно задротить литкод (хотя это хорошая идея), достаточно научиться рассуждать логически. У меня на литкоде дайбох если штук 10 решенных задач есть, однако на собеседованиях я решаю 90% задач. Литкод - это не цель и не поэма, которую нужно выучить наизусть, это всего лишь тренажер для отработки навыков логического мышления.
#алгоритмы
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤10👍5👎5❤🔥3🤮1🍌1
Скормила эту задачу чату гпт. Вот что он мне выдал:
*⃣ *⃣ *⃣
Думал на протяжении 16s
Короткий ответ: да — ровно тогда, когда в строке s существует фрагмент длины ≥ 2, который в какой-то момент встречается снова так, что его второе вхождение начинается в позиции, когда префикс до этой позиции уже напечатан. Формально: существует i (1 ≤ i ≤ n-1) и L ≥ 2 такие, что i + L ≤ n и s.substring(i, i+L) встречается в s.substring(0, i). В этом случае можно одну или несколько таких копий использовать и получить число операций < n.
Ниже — простая и надёжная реализация на JavaScript:
Сложность приведённого кода в худшем случае O(n³) в naive JS (из-за indexOf внутри двойного цикла), но на строках обычной длины это проходит быстро. Если нужна оптимизация для больших строк — можно применять суффиксный массив/дерево, Z-функцию или KMP/rolling hash, чтобы сократить до O(n²) или O(n).
*⃣ *⃣ *⃣
По-моему, какая-то лажа. Чат гпт решил искать не только группы из двух элементов, но и более длинные, хотя достаточно групп из двух элементов - они входят в более длинные. Еще и сложность кубическая.
Думал на протяжении 16s
Короткий ответ: да — ровно тогда, когда в строке s существует фрагмент длины ≥ 2, который в какой-то момент встречается снова так, что его второе вхождение начинается в позиции, когда префикс до этой позиции уже напечатан. Формально: существует i (1 ≤ i ≤ n-1) и L ≥ 2 такие, что i + L ≤ n и s.substring(i, i+L) встречается в s.substring(0, i). В этом случае можно одну или несколько таких копий использовать и получить число операций < n.
Ниже — простая и надёжная реализация на JavaScript:
// Возвращает true, если строку s можно набрать за число операций < s.length
function canBeTypedFaster(s) {
const n = s.length;
if (n <= 1) return false; // невозможно сократить
// для каждой позиции i — попробовать найти любую длину L>=2,
// такую что s[i:i+L] содержится в префиксе s[0:i]
for (let i = 1; i < n; i++) {
// максимальная длина, которую можем попытаться скопировать отсюда
const maxL = n - i;
// интересуют только L >= 2
for (let L = 2; L <= maxL; L++) {
const chunk = s.substring(i, i + L);
if (s.substring(0, i).indexOf(chunk) !== -1) {
return true;
}
}
}
return false;
}
// Примеры
console.log(canBeTypedFaster("tbank")); // false
console.log(canBeTypedFaster("mama")); // true
Сложность приведённого кода в худшем случае O(n³) в naive JS (из-за indexOf внутри двойного цикла), но на строках обычной длины это проходит быстро. Если нужна оптимизация для больших строк — можно применять суффиксный массив/дерево, Z-функцию или KMP/rolling hash, чтобы сократить до O(n²) или O(n).
По-моему, какая-то лажа. Чат гпт решил искать не только группы из двух элементов, но и более длинные, хотя достаточно групп из двух элементов - они входят в более длинные. Еще и сложность кубическая.
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Фронтенд кухня🥘
Дискуссия про применимость алгоритмических задач с собеседований в реальной работе получила новый виток. Сегодня в комментариях подкинули вот такую задачу с собеседования:
*️⃣*️⃣*️⃣
Вы хотите набрать строку s, состоящую из строчных латинских букв, в вашем…
*️⃣*️⃣*️⃣
Вы хотите набрать строку s, состоящую из строчных латинских букв, в вашем…
❤🔥8👎2🖕2❤1🤮1
Друг скинул еще одну задачу с собеседования: https://leetcode.com/problems/isomorphic-strings/. На ее решение у меня ушло около 7 минут. Решение:
Меня огорчило, что я не попала в 10% самых быстрых решений (beats 89.81%). Закинула чат гпт и он решил гораздо хуже (beats 32.05%).
Вот так этим вечером внезапно выяснилось, что чат гпт решает алгозадачи так себе - по крайней мере, те две, которые мы разбирали сегодня в канале, он решил хуже меня.
Для меня это еще один повод использовать алгозадачи на собесах 😎
var isIsomorphic = function(s, t) {
const dictS = {};
const dictT = {};
for (let i = 0; i < s.length; i++) {
const sChar = s[i];
const tChar = t[i];
if (!check(sChar, tChar, dictS) || !check(tChar, sChar, dictT)) {
return false;
}
}
return true;
};
function check(origin, replacer, map) {
if (map[origin]) {
return map[origin] === replacer
}
map[origin] = replacer;
return true;
}Меня огорчило, что я не попала в 10% самых быстрых решений (beats 89.81%). Закинула чат гпт и он решил гораздо хуже (beats 32.05%).
Вот так этим вечером внезапно выяснилось, что чат гпт решает алгозадачи так себе - по крайней мере, те две, которые мы разбирали сегодня в канале, он решил хуже меня.
Для меня это еще один повод использовать алгозадачи на собесах 😎
LeetCode
Isomorphic Strings - LeetCode
Can you solve this real interview question? Isomorphic Strings - Given two strings s and t, determine if they are isomorphic.
Two strings s and t are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced…
Two strings s and t are isomorphic if the characters in s can be replaced to get t.
All occurrences of a character must be replaced…
👎23🔥14👍6🤮3✍1🖕1
Мне интересно, дизлайк на предыдущий пост поставил человек, который попал в 10% самых быстрых решений? 🤔
👎21💩6🐳3🦄3🤣1🖕1
🍇 Немного о сортах типизации
Раз уж я заговорила про typenoscript, считаю своим долгом погрузить вас в эту тему.
Как вы знаете, typenoscript - это компилируемый язык со статической типизацией. В статически типизируемых языках в переменную можно присвоить только значение сопоставимого типа:
Однако не все знают, что языки программирования имеют разный взгляд на то, какой же тип является “сопоставимым”. Бывают языки с номинативной и структурной типизацией.
☄ Номинативная типизация
Языки с номинативной типизацией используют имя типа для того, чтобы считать, что тип является сопоставимым. Так типизация работает в Java: если мы объявляем значение и указываем тип, то присвоить в это значение мы можем только этот же самый тип либо потомок (логически, потомок тоже является тем же самым типом, просто с некоторыми уточнениями).
Если у нас есть другой класс, который совпадает по структуре, но не является наследником, присвоить его нельзя:
🚀 Структурная типизация
К удивлению всех бекендеров, которые заглядывали в мой код, typenoscript работает совсем не так. В typenoscript структурная типизация, поэтому он проверяет структуру, то есть содержание полей:
Typenoscript-у не важно, что тип по-другому называется - ему главное, что нужные поля имеются. Это может подкинуть вам такой неприятный сюрприз:
В typenoscript можно эмулировать номинативную типизацию при помощикостыля хака, о котором я писала здесь. В остальных случаях придется к ней привыкнуть и полюбить ❤️
#typenoscript
Раз уж я заговорила про typenoscript, считаю своим долгом погрузить вас в эту тему.
Как вы знаете, typenoscript - это компилируемый язык со статической типизацией. В статически типизируемых языках в переменную можно присвоить только значение сопоставимого типа:
const x: number = 42; // ок, в number можно присвоить number
const y: number = ‘abc’; // ошибка, в number нельзя присвоить строку
Однако не все знают, что языки программирования имеют разный взгляд на то, какой же тип является “сопоставимым”. Бывают языки с номинативной и структурной типизацией.
Языки с номинативной типизацией используют имя типа для того, чтобы считать, что тип является сопоставимым. Так типизация работает в Java: если мы объявляем значение и указываем тип, то присвоить в это значение мы можем только этот же самый тип либо потомок (логически, потомок тоже является тем же самым типом, просто с некоторыми уточнениями).
class Order { public String id; }
// PriorityOrder технически тоже является Order-ом, просто с дополнительными свойствами
class PriorityOrder extends Order { }
public class Main {
public static void main(String[] args) {
// ок, присваиваем в Order значение типа Order
Order o1 = new Order();
// PriorityOrder тоже можно присвоить в переменную типа Order, так это наследник
Order o2 = new PriorityOrder();
}
}Если у нас есть другой класс, который совпадает по структуре, но не является наследником, присвоить его нельзя:
class CustomerRequest { public String id; }
public class Main {
public static void main(String[] args) {
// Ошибка: нельзя присвоить в Order значение типа CustomerRequest, они никак не связаны через наследование
Order o3 = new CustomerRequest();
}
}К удивлению всех бекендеров, которые заглядывали в мой код, typenoscript работает совсем не так. В typenoscript структурная типизация, поэтому он проверяет структуру, то есть содержание полей:
type Order = { id: string };
type CustomerRequest = { id: string };
Function handleOrder(order: Order) {…};
сonst customerRequest: CustomerRequest = { id: ‘abc’ };
// ок, потому что структура двух типов совпадает
handleOrder(customerRequest);
Typenoscript-у не важно, что тип по-другому называется - ему главное, что нужные поля имеются. Это может подкинуть вам такой неприятный сюрприз:
type Phone = string;
type Email = string;
function sendSms(phone: Phone) {...}
const email: Email = 'test@mail.ru';
sendSms(email); // oк, потому что структура одна и та же, оба типа - строки
В typenoscript можно эмулировать номинативную типизацию при помощи
#typenoscript
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Фронтенд кухня🥘
Брендированные типы в typenoscript
Привет, с вами снова @devmargooo и сегодня мы с вами поговорим о типизации в приложении на typenoscript. Структурная типизация в typenoscript, в отличие от номинативной, определяет совместимость типов, основываясь не на названии…
Привет, с вами снова @devmargooo и сегодня мы с вами поговорим о типизации в приложении на typenoscript. Структурная типизация в typenoscript, в отличие от номинативной, определяет совместимость типов, основываясь не на названии…
🔥12💩8🤮6👍4❤3👎2😁1🖕1
Если вы придерживаетесь мнения, что алгоритмические задачи не нужно решать, это пост не для вас — на канале много других интересных постов😊 На этой неделе несколько человек написали мне с этим вопросом в личку, поэтому пишу пост для всех.
Тренировка этого навыка больше похожа на тренировку мышц в зале, чем на обучение фреймворку или языку программирования. Для того, чтобы изучить фреймворк или ЯП, в первую очередь нужно запоминать. Для того, чтобы учиться решать простые алгоритмические задачи, нужно размышлять. Это принципиально другой другой навык и к нему нужен другой подход: не поглощать информацию (учебники, статьи), а активно действовать, постепенно наращивая веса. Единственные необходимые знания для вас — основы вашего ЯП (циклы, условия, структуры данных и их методы).
Нужно начать с самых простых задач из тех, что вы можете решить самостоятельно и без подсказок. Большинство ребят способны решать простые задачи, такие как поиск максимума в массиве или обмен двух переменных значениями. В этом репозитории вы найдете еще простые задачи, с которыми можно поработать. Цель заключается в том, чтобы во время тренировки мысленно визуализировать алгоритм и представлять, как ведут себя разные структуры данных, что с ними можно делать и чего нельзя, какие операции выполняются похожим образом, а какие — совсем разным. Нужно решить много простых задач, после этого можно переходить к более сложным задачам (уровень easy на литкоде).
Главный принцип тренировок — задача не должна быть слишком сложной для вас. Задача для вас слишком сложная, если вы вообще не представляете, как ее решать, и пытаетесь вспомнить, видели ли вы когда-нибудь похожую. Для тренировки навыка важно не вспоминать, а размышлять. Наоборот, слишком простая задача — это задача, на решение которой в уме ушла секунда или меньше. “Заучивать” решения практически бесполезно — если позже вам попадется похожая задача, но с немного другими условиями, она будет для вас слишком сложной.
#алгоритмы
Please open Telegram to view this post
VIEW IN TELEGRAM
❤23🤮8👍7💯5👎3💩3❤🔥2🔥2🥰2🖕1
💥 Как React рендерит UI. Часть 1
Если вам когда-либо было сложно разобраться в порядке вызова эффектов в компоненте или вы просто хотите подготовиться к собеседованию, то это серия постов для вас.
📎 Рендеринг UI в React состоит из двух фаз: render и commit.
📌 Render фаза
Во время render фазы React вызывает функции компонентов. Ваши компоненты — это же обычные javanoscript функции, верно? Вот React эти функции и вызывает с переданными аргументами. В результате получается новый VDOM. После этого React React сравнивает старый VDOM с новым (этот процесс называется reconciliation) и определяет, какие изменения нужно внести (какие узлы добавить, какие узлы удалить и т.д.)
📌 Commit фаза
React вносит изменения в реальный DOM при помощи js методов вроде🙂 . После внесения изменения в DOM выполняются layout эффекты (
Рассмотрим пример и разберемся по шагам, что здесь происходит:
В этом примере:
*️⃣ Render фаза
1️⃣ Вызывается функция App. Вычисляется VDOM и изменения, которые нужно закоммитить в реальный DOM. Мы увидим лог “render”, потому что функция App была вызвана.
*️⃣ Commit фаза
2️⃣ React обновляет реальный DOM
3️⃣ Выполняется useLayoutEffect. Мы увидим лог “useLayoutEffect”
4️⃣ Изменения отобразятся на экране, и пользователь увидит Hello world.
5️⃣ Выполнится useEffect, и мы увидим лог “useEffect”
В следующих постах посмотрим, как изменится этот флоу, если эффекты вносят изменения в DOM или состояние.
#react
Если вам когда-либо было сложно разобраться в порядке вызова эффектов в компоненте или вы просто хотите подготовиться к собеседованию, то это серия постов для вас.
Во время render фазы React вызывает функции компонентов. Ваши компоненты — это же обычные javanoscript функции, верно? Вот React эти функции и вызывает с переданными аргументами. В результате получается новый VDOM. После этого React React сравнивает старый VDOM с новым (этот процесс называется reconciliation) и определяет, какие изменения нужно внести (какие узлы добавить, какие узлы удалить и т.д.)
React вносит изменения в реальный DOM при помощи js методов вроде
appendChild, removeChild и т.п. Но это не приводит к их немедленному отображению на экране — js однопоточный и этот поток занят выполнением js кода useLayoutEffect). Они уже могут использовать реальный DOM (например, для вычисления размеров элементов) и вносить в него правки. Только после этого браузер отрисовывает новый UI на экране, после чего выполняются эффекты useEffect.Рассмотрим пример и разберемся по шагам, что здесь происходит:
function App() {
useLayoutEffect(() => console.log('useLayoutEffect'));
useEffect(() => console.log('useEffect'));
console.log('render');
return <div>hello world</div>;
}В этом примере:
В следующих постах посмотрим, как изменится этот флоу, если эффекты вносят изменения в DOM или состояние.
#react
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤28🔥10🤮6💩3👎2💘2
💥 Как React рендерит UI. Часть 2
В прошлой серии мы поговорили с вами о том, что рендеринг в React состоит из двух фаз — render и commit. В render фазе вычисляются новые VDOM и Fiber tree, в commit фазе сначала обновляется DOM, затем выполняются useLayoutEffect, после чего следует отрисовка и, наконец, выполняются useEffect.
Сегодня мы рассмотрим useLayoutEffect подробнее.
Многие из вас знают, что в useLayoutEffect можно подшаманить UI перед отрисовкой и тогда верстка не будет прыгать. Например, в следующем кейсе пользователь сразу увидит красивый нежно-розовый прямоугольник без скучного серого перед ним:
Это происходит за счет того, что useLayoutEffect выполняется перед отрисовкой. Браузер построил DOM с серым прямоугольником, затем выполнил js код с useLayoutEffect, в котором содержится смена цвета. После этого браузер внес изменения в DOM и затем наконец отрисовал интерфейс.
А что произойдет, если мы в useLayoutEffect будем менять состояние? Помним, что обновление состояния происходит асинхронно — новое значение появится только в следующем рендере. Как думаете: в примере ниже пользователь сначала увидит серый прямоугольник или сразу розовый?
Ответ на этот вопрос я напишу позже, а пока вы можете делиться вашими догадками в комментариях :)
#react
В прошлой серии мы поговорили с вами о том, что рендеринг в React состоит из двух фаз — render и commit. В render фазе вычисляются новые VDOM и Fiber tree, в commit фазе сначала обновляется DOM, затем выполняются useLayoutEffect, после чего следует отрисовка и, наконец, выполняются useEffect.
Сегодня мы рассмотрим useLayoutEffect подробнее.
Многие из вас знают, что в useLayoutEffect можно подшаманить UI перед отрисовкой и тогда верстка не будет прыгать. Например, в следующем кейсе пользователь сразу увидит красивый нежно-розовый прямоугольник без скучного серого перед ним:
// index.css
.rect { width: 300px; height: 200px; background: grey; }
// App.tsx
export default function App() {
const rect = useRef<HTMLDivElement | null>(null);
useLayoutEffect(() => {
if (!rect.current) return;
rect.current.style.backgroundColor = "pink";
}, []);
return <div className="rect" ref={rect}></div>;
}
Это происходит за счет того, что useLayoutEffect выполняется перед отрисовкой. Браузер построил DOM с серым прямоугольником, затем выполнил js код с useLayoutEffect, в котором содержится смена цвета. После этого браузер внес изменения в DOM и затем наконец отрисовал интерфейс.
А что произойдет, если мы в useLayoutEffect будем менять состояние? Помним, что обновление состояния происходит асинхронно — новое значение появится только в следующем рендере. Как думаете: в примере ниже пользователь сначала увидит серый прямоугольник или сразу розовый?
function sleep() {
const start = Date.now();
while (Date.now() - start < 2000) {}
}
export default function App() {
const [color, setColor] = useState("gray");
useLayoutEffect(() => {
sleep(); // спим 2 секунды
setColor("pink");
console.log(color); // серый - обновление произойдет перед следующим рендером
}, []);
return (
<div
style={{
width: "300px",
height: "200px",
background: color,
}}
></div>
);
}Ответ на этот вопрос я напишу позже, а пока вы можете делиться вашими догадками в комментариях :)
#react
🔥15❤11🤮6👍3👎2💩2
Какой прямоугольник пользователь увидит сначала в задаче выше?
Anonymous Poll
53%
➖серый
47%
🔥6🤮6❤5👍3👎3💩3
💥 Как React рендерит UI. Часть 3
Мнения разделились. Правы оказались те, кто выбрал романтичный розовый цвет 💗 (пруф). Но подождите… ведь переменная состояния обновляется только в следующем рендере, верно?
Так и есть. При вызове setState внутри useLayoutEffect React прерывает текущую commit фазу и сразу запускает новую render фазу. Таким образом, после первого рендера пользователь ничего не увидит — до стадии отрисовки React не дошел. А вот после второго увидит розовый прямоугольник🌸
В следующей серии поговорим о том, что будет, если в дело вступит useEffect💫
#react
Мнения разделились. Правы оказались те, кто выбрал романтичный розовый цвет 💗 (пруф). Но подождите… ведь переменная состояния обновляется только в следующем рендере, верно?
Так и есть. При вызове setState внутри useLayoutEffect React прерывает текущую commit фазу и сразу запускает новую render фазу. Таким образом, после первого рендера пользователь ничего не увидит — до стадии отрисовки React не дошел. А вот после второго увидит розовый прямоугольник
В следующей серии поговорим о том, что будет, если в дело вступит useEffect
#react
Please open Telegram to view this post
VIEW IN TELEGRAM
❤19👍10🔥7👎4🤯4🤮2🤡1
💥 Как React рендерит UI. Часть 4
В прошлый раз мы с вами убедились в том, что
Ок, а что насчет
#react
В прошлый раз мы с вами убедились в том, что
useLayoutEffect действительно блокирует рендер. Если в useLayoutEffect есть “тяжелый” код (в нашем примере это была задержка в две секунды), то интерфейс зависнет, а затем покажет обновленный UI — с правками, внесенными в useLayoutEffect. Ок, а что насчет
useEffect? Мы знаем, что он выполняется после отрисовки. Как думаете, код ниже зависнет на 2 секунды прежде чем отобразить прямоугольник на экране или нет? function sleep() {
const start = Date.now();
while (Date.now() - start < 2000) {}
}
export default function App() {
const [color, setColor] = useState("gray");
useLayoutEffect(() => { setColor("pink"); }, []);
useEffect(() => { sleep(); // спим 2 секунды }, []);
return (
<div
style={{
width: "300px",
height: "200px",
background: color,
}}
></div>
);
}#react
🤡10🔥6🥰5❤3👎3💩3👍1
💩9👍8🤡6❤4👎2🤮1
💥 Как React рендерит UI. Часть 5
Вопреки ожиданиям голосующих, в примере выше React зависнет на две секунды, прежде чем что-то покажет на экране. Пруф здесь. Давайте разберемся, почему так.
Ранее мы выяснили, что при изменении состояния в
Но тут появляется важная деталь: прежде чем начать новый рендер, React обязан выполнить эффекты предыдущего. Это официальная гарантия:
Именно поэтому в нашем примере после
#react
Вопреки ожиданиям голосующих, в примере выше React зависнет на две секунды, прежде чем что-то покажет на экране. Пруф здесь. Давайте разберемся, почему так.
Ранее мы выяснили, что при изменении состояния в
useLayoutEffect React пропустит браузерную отрисовку и перейдет в рендер фазу. В нашем примере мы как раз меняем состояние в useLayoutEffect, именно поэтому мы должны пропустить отрисовку и перейти к рендер фазе. Но тут появляется важная деталь: прежде чем начать новый рендер, React обязан выполнить эффекты предыдущего. Это официальная гарантия:
Even in cases where useEffect is deferred until after the browser has painted, it’s guaranteed to fire before any new renders. React will always flush a previous render’s effects before starting a new update.
Именно поэтому в нашем примере после
useLayoutEffect React вызывает useEffect. В нашем случае useEffect содержит блокирующую операцию, поэтому интерфейс подвиснет. Затем React доходит до ререндера, и только после этого UI мы наконец увидим наш UI на экране🌸#react
🔥11👍8🤮8😱5💩4❤3☃2👎2🫡2🤨1💘1
💥 Как React рендерит UI. Часть 6
Вдогонку к вчерашнему посту: а вот такой кейс сработает ожидаемо — мы сразу увидим розовый прямоугольник, и только потом интерфейс подвиснет. Все потому, что в этом случае рендер будет только один и useEffect сработает после отрисовки.
#react
Вдогонку к вчерашнему посту: а вот такой кейс сработает ожидаемо — мы сразу увидим розовый прямоугольник, и только потом интерфейс подвиснет. Все потому, что в этом случае рендер будет только один и useEffect сработает после отрисовки.
function sleep() {
const start = Date.now();
while (Date.now() - start < 2000) {}
}
function App() {
useEffect(() => {
sleep(); // спим 2 секунды
}, []);
return (
<div
style={{
width: '300px',
height: '200px',
background: 'pink',
}}
></div>
);
}#react
🤮11👍10❤7💩4👎3🔥3
Когда я в 2017 году стажировалась в ЦФТ, нам рассказывали про одного парня, которому нужно было сделать класс для вычисления скидок, и он назвал его Skidon. Его так и прозвали — Дима Скидон. Сейчас на рынке работодателя вы просто не найдёте работу с таким кодом.
Хороший английский нужен не только для того, чтобы подбирать подходящие названия для переменных и классов, но и чтобы общаться с командой на равных, когда будете выходить на международный рынок🚀 💵
Если хотите подтянуть язык, с этим помогут в онлайн-школе разговорного английского Authentic Pigeon
Ребята соберут кастомную программу, чтобы вы быстрее добрались до уровня английского, с которым можно смело искать работу в зарубежном проекте 😎
Студент школы — Иван
Узнать подробнее о занятиях и записаться на бесплатный демо-урок
Реклама. Моисеева Анастасия Андреевна, ИНН 270393875959. Erid: 2VtzqwUv25N
Хороший английский нужен не только для того, чтобы подбирать подходящие названия для переменных и классов, но и чтобы общаться с командой на равных, когда будете выходить на международный рынок
Если хотите подтянуть язык, с этим помогут в онлайн-школе разговорного английского Authentic Pigeon
Ребята соберут кастомную программу, чтобы вы быстрее добрались до уровня английского, с которым можно смело искать работу в зарубежном проекте 😎
Абсолютно кайфую от подхода ребят. Занятия тут это не потогонка, а крутой дружеский разговор.
Студент школы — Иван
Узнать подробнее о занятиях и записаться на бесплатный демо-урок
Реклама. Моисеева Анастасия Андреевна, ИНН 270393875959. Erid: 2VtzqwUv25N
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
PRO английский ⚡️ Authentic Pigeon
Бот онлайн-школы разговорного английского для профессионалов с карьерными целями. Наш канал — @authenticpigeon
💩13❤9👎6🥰5🤡5👍3🥱2🗿1