Чат: @prog_way_chat Разборы вопросов и задач с собеседований, мысли, полезные материалы и просто вещи, что мне интересны из мира IT Полезности и навигация в закрепе По всем вопросам: @denisputnov
Зачем нужен DOCTYPE в HTML
Вроде бы все знают, что в начале каждого HTML документа необходимо указывать магический тег <!DOCTYPE html>
, но мало кто может объяснить зачем это нужно делать. Все делают, вот и я делаю тоже. В этом посте расскажу зачем.
Этот тег - отдельная структура в языках разметки, которая называется Document Type Definition или аббревиатура DTD. Похожие определяющие тип документа теги или свойства встречаются, например, в SVG или XML:
<?xml version="1.0" encoding="UTF-8"?>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
>
<!DOCTYPE html>
Лишние аргументы и arguments
В прошлом посте я рассказывал о перегрузке функций, где обещал подробнее рассказать о псевдомассиве arguments
. Этот пост как раз об этом.
Итак, этот псевдомассив доступен только внутри функции, объявленной с помощью ключевого слова function
. В стрелочных функциях этого псевдомассива нет.
function foo() {
console.log(arguments)
}
foo(1,2,3)
// { '0': 1, '1': 2, '2': 3 }
arguments
— объект? На самом деле это объект, подобный массиву. Это обычный объект, у которого реализован геттер length
и к которому можно применять некоторые другие операторы итерируемых сущностей. Но у arguments
нет других методов массива, например shift
или push
.function sum() {
return [...arguments].reduce((acc, cur) => acc + cur, 0)
}
arguments
, потому что у этого псевдомассива нет метода reduce
. Таким образом получается функция, которая соответствует задаче.sum(1,2,3,4,5) // 15
sum(1,2,3,4,5,6,7,8,9) // 45
sum(10, 20) // 30
sum() // 0
arguments
, но об этом в другой раз. А пока что у меня всё. Спасибо за прочтение и интерес.Специфичность CSS
Не самый простой для многих вопрос, который для некоторых разработчиков даже Middle уровня будет фатальным. Но не для нас 🙂
Итак, специфичность указывает на то, какой стиль будет применён к элементу. На это влияет три показателя:
— Место определения селектора
— Вес селектора
— Директива !important
Разберем их по порядку:
• Специфичность выше, если свойство объявлено ниже. То есть в примерах
body {
color: black;
color: red;
}
div {
width: 100px;
}
div {
width: 400px;
}
body
будет иметь правило color: red;
, а элемент div
будет иметь правило width: 400px;
, так как эти свойства объявлены ниже и "перезаписали" вышеописанные свойства.div = 1
div.className = 1 + 10 == 11
#id .className = 100 + 10 == 110
div > span = 1 + 1 == 2
!important
, то в таком случаем специфичность такого правила будет максимальной и применится то правило, что помечено директивой.div {
color: red !important;
}
div {
color: blue;
}
div
будет применено правило color: red;
.Какие типы данных есть в JavaScript
В любом языке базовым вопросом будет назвать типы данных и JavaScript тут не исключение. Разберем один из самых частых вопросов на собеседовании.
Итак, в JavaScript есть 6 типов:
- number
- string
- boolean
- null
- undefined
- object
Первые 5 являются примитивами, а object
является сложным типом данных. Также ES6 принёс в язык типы BigInt
и Symbol
.
Из особенностей:
typeof null // 'object'
typeof [] // 'object'
typeof (() => {}) // 'function'
typeof function() {} // 'function'
typeof NaN // 'number'
const a = new Set()
const b = new Map()
typeof a // 'object'
typeof b // 'object'
typeof null === 'object'
— это официальная ошибка, которая сохраняется ради обратной совместимости кода. На самом деле null
— это отдельный примитив.Map
, Set
, WeakMap
, WeakSet
— это объекты.typeof
как 'function'
, на самом деле, функция — это тоже объект. Почему так мы разберём чуть позже, но вообще функции называют объектами первого класса. Так что на самом деле функция — это тоже объект.typeof NaN === 'number'
. Вот такой прикол вам оставили разработчики, да. Not A Number
— это инстанс Number
. Для проверки NaN
есть специальная глобальная функция isNaN()
.Итерирование по сущностям: filter
Код из примеров очень сложно читать в самом Telegram из-за его размера, так что все примеры для простоты я перенёс в телеграф.
Ранее я уже рассматривал методы итерирования по массиву map и reduce. Предлагаю дополнить этот список методом filter
.
1. filter
возвращает новый массив без изменения старого
2. Параметром принимает callback
, который должен вернуть значение типа boolean
или значение, которое будет преобразовано к boolean
, например пустую строку
3. В новый массив попадут все значения, для которых функция callback вернула значение, подобное true
Например, необходимо получить список всех положительных чётных чисел из списка (пример 1)
Или из списка customers
нужно получить всех покупателей, которые подтвердили свой аккаунт (пример 2)
В результате получим два искомых покупателя. То есть из объекта даже можно возвращать одно из полей, не применяя к нему никаких вычислений.
Полная сигнатура метода: filter(function callback(element, index, array) { ... }, thisArg)
Где callback
- функция, а thisArg
- значение, которое будет использовано как this
в callback
функции.
И filter
, как метод, можно использовать в цепочке, тем самым оформляя решения крайне читабельно и красиво, например:
Написать функцию, которая на вход получает массив слов, а возвращает общую длину всех слов палиндромов. Пример сказочный, но допустим (пример 3)
Комбинацией трёх этих методов мы реализуем функцию, которая даст нам правильный ответ.
Чаще всего хватает одного метода или комбинации двух из трёх методов. Эта задача усложнена намеренно, чтобы оправдать использование трёх методов сразу. И даже эту задачу можно решить лишь с использованием filter
и reduce
, map
тут избыточен.
Есть еще много способов итерации по сущностям, например те же разные виды цикла for
. Их я разберу чуть позже. Ну а пока, спасибо за прочтение, это важно для меня ❤️
#javascript #web #theory #useful
Сказ о том, как я HTML в JPG конвертировал...
Обычно, когда я пишу посты в канал, я использую фотошоп для создания картиночки к нему. Эта картинка присутствует у подавляющего большинства постов и я думаю для многих это уже неотъемлемая часть стиля всего канала. И часто эта самая картинка — большая проблема для меня. Для её создания мне нужен сам фотошоп, время, куча ненужных действий и вот это вот всё неприятное. И пусть я делаю всё это по шаблону, который подготовил заранее, даже тут моя лень находит способ помешать мне. А лень — двигатель прогресса, это уж точно.
В общем, проблем несколько:
— Лень
— Занимает относительно много времени и не приносит удовольствия
— Посты можно оформить только с ПК
— Я счастливый обладатель MacBook на M1, так что для нормальный работы в Photoshop нужно тратиться на лицензию
Я решил найти другое решение: бесплатное, быстрое, удобное и кросс-платформенное. И нашел.
Для решения задачи я хотел использовать Python
, но решение это было не лучшее. Нет нормального API
для работы с DOM
элементами, нужна песочница для запуска браузера, работает медленнее, а самое главное - на Python
у меня гораздо меньше опыта. Я реализовал рабочий вариант на imgkit
достаточно быстро, но он не устроил меня, код удалён.
Ну и, соответственно, я решил использовать node js
. Я имею куда больше опыта c node
и javascript
, так что рабочее решение, которое по моим тестам работало быстрее решения на Python
в 7.5 раз, было готово меньше чем через 20 минут.
Я быстро накатил первую попавшуюся из поиска библиотеку node-html-to-image, воспользовался неплохой документацией, сверстал максимально странный, но рабочий макет и вот, мой html
конвертируется в изображение за, в среднем, 2.4 секунды. Ещё за полчаса я изучил библиотеку node-telegram-bot-api и создал на основе скрипта-генератора удобный для себя интерфейс для управления им. Теперь картинки к моим постам генерируются на бесплатном хостинге heroku
, и делают они это через API
бота в телеграм. Процесс выглядит так.
В итоге, процесс создания картинки максимально упрощён. Я могу оформить пост с любого устройства, где поддерживается клиент телеграмма (то есть даже с утюга), мне не нужно платить за подписку на Photoshop и я даже могу делегировать создание постов на кого-то куда проще.
Всё это написано крайне криво, неказисто, без нормальной архитектуры и, даже, как такового код-стайла, в паре файликов. Но оно работает. И мне этого достаточно. Я не вижу смысла тратить время на вылизывание кода, которым буду пользоваться только я, это элементарно экономически не выгодно. Но если вдруг перед кем-то встанет такая-же задача, то на моё решение можно посмотреть здесь.
Можно было написать лучше, может быть на питоне это генерировалось бы за миллисекунды, мне плевать. Оно работает и выполняет свою задачу более чем удовлетворительно. Картинка к этому посту уже сделана через бота. Сравнив её с прошлыми, где все сделаны вручную, я думаю, вы оцените качество результата. Можете, кстати, поискать на картинке пасхалку. Милая штука, на мой взгляд.
Делюсь. Вот. Спасибо за прочтение, это правда важно для меня.
#blog #useful #github #design #chatbot
Что такое this
Часто понятие контекста this
у новичков и не только вызывает массу вопросов.
Если максимально просто, то контекст — это объект. Это первый пункт, который необходимо запомнить. Контекст — это всегда объект, которому принадлежит исполнение кода. Что это значит?
Разберем на примере браузера:
Допустим, что есть функция foo()
function foo() {
console.log(this === window)
}
true
. Это происходит потому что наша функция вызывается относительно глобального объекта window
. Вызов принадлежит объекту window
. Более того,this.hasOwnPropery('sayHi') === true
this
в этом случае действительно равно объекту window
.
class Bar {
constructor(number) {
this.number = number
this.name = 'denis'
}
showThis() {
console.log(this)
}
}
const bar = new Bar(5)
bar.showThis()
Bar
, в методе constructor
объявляем контекст нашего класса. При вызове метода showThis
мы увидим ожидаемый объект:
{
name: "denis",
number: 5
}
showThis
вызывается относительно объекта bar
и его контекста. Поэтому мы видим созданный объект из конструктора класса. Если бы на вход к конструктору было подано другое значение, то мы получили бы и, соответственно, другой контекст. Отсюда получаем самые важные свойства контекста:this
— это лишь ссылка на запись в памяти, которая указывает на контекст. А если это всего лишь ссылка, то значит мы можем управлять контекстом, вау! На управлении контекстом реализованы несчетное количество паттернов и концепций. Об управлении контекстом мы поговорим позже, а за управление контекстом отвечают методы call,apply и bind. Их нужно знать и уметь применять, ждите новый пост. window
, в nodejs
это объект global
. "use strict;"
или без него. О том, что такое "use strict;"
я тоже скоро расскажу.DOM-API
ключевое слово this указывает на объект event.currentTarget()
. Для понимание этого пункта рассмотрите код ниже.
<button onclick="console.log(this.innerHTML)">
Текст внутри кнопки
</button>
"Текст внутри кнопки"
. Infinity в JavaScript
В JavaScript существуют специальные значения: Infinity и -Infinity. Эти значения используются как границы в алгоритмах как бесконечно большое и бесконечно малое значение соответственно.
Получить такие значения можно явно:
let a = Infinity
1 / 0 // Infinity
-1 / 0 // -Infinity
JavaScript: в чем разница null и undefined?
Супер популярный вопрос с собеседований, ответ на который висит почти везде. Пусть и тут будет.
1. Основное отличие: null присваивается только явно самим разработчиком, в то время как undefined интерпретатор может присвоить самостоятельно.
undefined присваивается к переменным, для которых значение неопределено, например:
var name;
console.log(name) // undefined
name = "Denis"
console.log(name) // Denis
var name = null
typeof null // 'object'
typeof undefined // 'undefined'
Что такое callback функция
Снова больше двух недель постов не было, сессия убивает меня не только морально, но и физически.
Сегодня обсудим базовое понятие в теории языков, которое актуально везде.
Callback функция — это функция, которая должна быть вызвана после выполнения чего-то (чаще всего другой функции). Таким образом мы можем контролировать порядок вызова функции.
Функция высшего порядка — функция, которая принимает в качестве аргумента другую функцию и/или возвращает новую функцию.
Чаще всего callback функции рассматриваются вместе с понятием функций высшего порядка. Оно и понятно. В более глобальном смысле, callback функция — функция, переданная в другую функцию в качестве аргумента, позже вызванная. Сначала в стеке вызова появится функция высшего порядка, а потом наш callback. Говорящее название — функция обратного вызова.
Рассмотрим на примере:
const logSuccess = () => console.log("Запрос выполнен успешно")
const fetchData = async (uri, callback) => {
const data = await fetch(uri)
... // обрабатываем результат запроса
callback() <-- вызов callback'а
return json
}
Итерирование по сущностям: reduce
Уже чуть ранее мы разбирали что такое метод map для массива, а теперь пополним список методом reduce
. reduce
— это тоже метод массива. И его применение в некоторых случаях очень упрощает работу. reduce и map очень похожи. Оба метода последовательно к каждому элементу массива применяю какую-то функцию, но если map как результат работы возвращает новый массив, то метод reduce
возвращает какое-то единственное результирующее значение.
Допустим, у нас есть массив чисел:
const numbers = [1,2,3,4,5,6,7,8,9]
reduce
, то сумму чисел массива мы скорее всего найдём так:
let sum = 0
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i]
}
const sum = numbers.reduce((sum, current) => sum + current)
filter
, reduce
и map
в основном проявляется в их совместном использовании. Ну и, субъективно, reduce выглядит куда более читабельно.
array.reduce(reducer, initialValue = 0)
reducer = (accumulator = initialValue, currentValie, index, array) => ...
А в чём все таки разница между var, let и const?
Начал писать другой пост и понял, что мне не хватает описания этой темы, поэтому слегка переключился сюда. Тема максимально простая, даже тривиальная, но знать и понимать как всегда важно. А еще советую прочитать пост по областям видимости, он будет важен сегодня. Итак:var
- устаревший способ объявления переменных, который был актуален до выпуска ES6. Ключевое слово var
объявляет переменную внутри функциональной области видимости, то есть внутри функции, что и следует из названия. Переменная, объявленная внутри функции, снаружи функции доступна не будет:
function foo() {
var i = 0
}
console.log(i) // i is not defined
let
и const
ещё уже — она блочная:
if (true) {
var i = 0
let k = 0
}
console.log(i) // 0
console.log(k) // k is not defined
let
и const
не доступны уже за пределами блока. MVC на пальцах
Приветики-пистолетики. Вот так вот интересно зайду сегодня, могу себе позволить.
В этом посте хочу поговорить о такой прекрасной штуке, как MVC в применении к веб-разработке. Крайне популярная тема для всей Front-End движухи в принципе, которую требуют знать практически у каждого джуна. Поэтому сегодня об этом.
MVC — это паттерн проектирования. Аббревиатура от слов Model, View, Controller. И, несмотря на такую большую распространненность и важность в целом, всё максимально просто. Суть заключается в том, что приложение разбивается на 3 блока, каждый из которых имеет свои функции. Три этих блока, соответственно, — модель, представление и контроллер.
Рассмотрим каждый из блоков отдельно:
• Модель — это блок, который отвечает за данные нашего приложения, и, по сути, во многом определяет его. Этот блок кода определяет данные и способы взаимодействия с ними.
• Представление — блок, который отвечает исключительно за представление наших данных. Этот блок кода отвечает только за то как будет выглядеть наше приложение и не несет в себе никакой бизнес-логики.
• Контроллер — блок, который организовывает взаимодействие модели и представления. В контроллере мы вешаем прослушку событий, взаимодействуем с данными и в целом организуем в этом блоке всю бизнес-логику нашего приложения.
На примере,
Ноутбук: монитор (представление), память (модель), и процессор (контроллер)
Ресторан: вкусный кофе (представление), официант (контроллер), и повар (модель)
Кофе - представление, тут вопросов быть не должно.
Повар - модель, потому что именно он знает как сварить великолепный кофе.
Официант - связующее звено. Он никак не влияет на данные, никак не влияет на сам кофе. Просто перемещает его.
На таких тривиальных примерах можно уйти гораздо дальше, и я надеюсь, что каждому хватит интереса на это.
Спасибо за прочтение, это важно ❤️
#theory #patterns
Что такое область видимости переменных
Тема, которую я хочу осветить, достаточно большая, так что пост будет снова сдвоенный. Сейчас мы поговорим о том что такое область видимости, а следующий пост будет по механизму замыканий, скоро.
Чтож, область видимости переменных в вашей программе - это та область, откуда переменная доступна. И тут нужно понимать, что видимость переменных распространяется исключительно наследовательным путем (в виде дерева, графа). Это значит, что переменные из области родителя доступны в детях, но не наоборот. Что за дети и родители?
Рассмотрим пример:
const fib = [ 1, 1, 2, 3 ]
const sayHello = (name) => {
const surname = "Putnov"
console.log(`Hello, ${name} ${surname}`)
}
{
const channel = {
name: "progway",
theme: "blog"
}
}
fib // [ 1, 1, 2, 3 ]
surname // Error: is not defined
channel // Error: is not defined
const identificators = [11, 24, 93, 8]
function foo() {
console.log(identificators[0]) // 11
}
foo()
{
var name = "progway"
const age = "less than 1 year"
}
name // "progway"
age // Error: is not defined
Обработка асинхронного кода.
Этот пост - как продолжение к предыдущему, так что сначала советую прочитать именно его.
В JavaScript мы имеем несколько возможных вариантов обработки асинхронного кода:
- асинхронные callback'и,
- промисы,
- синтаксис async/await.
Callback'и в этом посте мы не будем рассматривать. Остаются промисы и синтаксис async/await, которые идет, конечно, отдельными пунктами, но вообще-то стоит понимать, что в JavaScript операторы async/await - это не более чем синтаксический сахар, надстройка над промисами. Отсюда следует и то, что промисы и новый синтаксис могут использоваться совместно.
Перепишем код с использованием промиса:
new Promise((resolve, reject) => {
setTimeout(() => {
resolve(console.log("Сообщение через 1500 мс"))
}, 1500)
}).then(() => {
console.log("Второе сообщение");
})
Promise
через конструктор.resolve
и reject
. Это две функции. Особенно углублять не будем, но когда вызывается resolve - промис считается выполненным, а когда reject
- выбрасывается ошибка. then
гарантированно выполнится после промиса.
// console out
Сообщение через 1500 мс
Второе сообщение
new Promise(...).then(...).then(...).then(...) ... .catch(...)
catch
. Он нам нужен для обработки ошибок в промисах. fetch
запрос. Fetch
позволяет нам делать HTTP запросы и позвращает промис.
async function getDataFromServer() {
// сделаем запрос
const response = await fetch('https://jsonplaceholder.typicode.com/todos')
// обработаем данные
const data = await response.json()
return data
}
async function getDataFromServer() {
// сделаем запрос и преобразуем полученные данные
return await fetch('https://jsonplaceholder.typicode.com/todos')
.then(response => response.json())
}
Различия блочных и строчных элементов
Простой вопрос с собеседования, в котором путается много новичков. Предлагаю расставить всё по местам.
Итак, все элементы в HTML делятся на две основные группы: блочные и строчные.
Блочные элементы - это та группа элементов, которые при размещении занимают всю доступную ширину. Блочные элементы всегда становятся друг под другом.
Строчные элементы - это группа элементов, ширина которых соответствует ширине контента внутри них. В отличии от блочных элементов, они располагаются в строку, если для этого хватает места.
Также тип элемента можно изменять при помощи стилей. Если блочному элементу необходимо задать поведение строчного, то достаточно для него указать правило display: inline
. Для обратной ситуации по аналогии указывается display: block
.
Также существует что-то среднее между блочным и строчным элементом. Для этого необходимо задать правило display: inline-block
.
Пример блочных элементов: <div>, <p>, <ul>, <h1>
Пример строчных элементов: <a>, <span>, <strong>, <img>
Из интересного, в более старых версиях HTML было так, что в блочные элементы можно было вкладывать как блочные, так и строчные элементы. А в строчные можно было вложить только строчные. Сейчас такого нет. В HTML5 порядок вложения тегов ни на что не влияет. В новой спецификации используется категориальное деление тегов. Об этом в других постах.
И на этом всё. Достаточно просто, но почему-то вызывает много путаницы. Да и для повторения лишним не будет. Спасибо за прочтение, это важно для меня ❤️
#web #theory
Есть ли в JavaScript перегрузка функций?
Достаточно интересный вопрос, на который без дополнительных наводящих вопросов от интервьюера мало кто ответит. Чтобы ответить, есть ли перегрузка функций в JavaScript, необходимо узнать что это вообще такое.
Перегрузка функций — или по другому «полиморфизм функций» — это понятие, которое встречается в языках программирования. Если язык поддерживает перегрузку функций, то у разработчика появляется возможность определить две функции с разной логикой, но с одинаковым именем. При вызове интерпретатор сам выберет нужную:
function foo(x, y) {
...
}
function foo(x, y, z ) {
...
}
foo(x, y) // вызовется первая функция
foo(x, y, z) // вызовется вторая функция
foo
и при вызове функции с разным количеством аргументов мы будем вызывать одну и ту же функцию, только:foo(1, 2)
// x = 1
// y = 2
// z = undefined
foo(1, 2, 3)
// x = 1
// y = 2
// z = 3
foo
, которая вызывается с любыми аргументами. А уже внутри она может посмотреть, с чем вызвана и по-разному отработать. arguments
. О нём и пойдёт речь в следующем посте.Методы управления контекстом вызова
Ранее мы разбирали что такое this и там я пообещал рассказать о методах call
, apply
и bind
. Этот пост как раз об этом.
Итак, все эти 3 метода созданы для управления контекстом вызова функции. Давайте рассмотрим пример:
const person = {
name: "Deins",
greet(greeting = 'Hi') {
console.log(`${greeting}, ${this.name}`)
}
}
const channel = {
name: "progway"
}
// Hi, Denis
person.greet()
// Hello, progway
person.greet.call(channel, 'Hello')
// Привет, Денис
person.greet.apply({name: 'Денис'}, ['Привет'] )
const greetMax =
person.greet.bind({name: "Макс"}, 'Привет')
// Привет, Макс
greetMax()
person
есть метод greet
, который за контекст вызова берёт как раз объект person
. Но если мы хотим применить к этому методу другой контекст, например созданный заранее объект channel
или новый произвольный объект, то необходимо использовать вышеописанные 3 метода.call
, apply
— применяют новый контекст к функции, принимая новый контекст первым параметром, а далее вызывают функцию с указанными аргументами. call
принимает аргументы функции через запятую, а apply
принимает их списком. Это основное отличие между этими двумя методами.bind
— так же применяет контекст и через запятую принимает параметры для вызова, НОapply
и call
сразу же вызывают функцию и возвращают её результат, а метод bind
создает новую функцию относительно аргументов и контекста, но не вызывает её. Такую функцию мы можем сохранить в переменную и вызвать позже.Что такое чистая функция
Я часто смотрю видео с собеседований и этот вопрос встречается чуть ли не в каждом втором собеседовании на разных уровнях. И больше всего удивляет, что даже мидлы не знают что это такое и не могут дать точного определения. А я могу 🙂
Чистая функция — это функция, обладающая сразу двумя свойствами:
1. Функция зависит только от входных параметров, на одинаковых наборах входных значений возвращается один и тот же результат вне зависимости от внешних факторов.
2. Функция не влияет на что-либо вне себя. Чистая функция не может изменять внешние переменные, управлять чем-либо извне, создавать файлы, изменять входные параметры по ссылкам и т.д.
Максимально просто, но почему-то знают не все.
Также я подготовил примеры чистых и не чистых функций. Размещаю их по ссылкам, чтобы не раздувать пост в объёме. Примеры на JavaScript
, но код более чем читаемый.
Чем чистые функции так полезны и почему это хорошо? Они ведут себя предсказуемо и их легко тестировать. Чистые функции поддаются тестированию проще других, не мутируют, не вызывают непоняток. Поэтому они так ценятся и в без того проблемном JavaScript
. И в других языках, конечно.
На этом всё. Спасибо за прочтение ❤️
#javascript #theory
Проблема 0.1 + 0.2
Часто на собеседовании можно встретить такой вопрос:
Что будет выведено в консоль?0.1 + 0.2 == 0.3 // ?
Любой адекватный человек, который знает школьную математику, ответил бы, что в консоли будет выдано значение true
, но это неверный ответ. Будет false
.0.1 + 0.2 === 0.30000000000000004
Что за бред? Почему? Зачем?
У этой проблемы есть отдельное название и даже свой сайт, где вы можете посмотреть в каких языках встречается эта проблема. И суть заключается в том, что система счисления разная.
Представление нашей десятичной алгебры в компьютере задано в двоичной системе счисления, как байт код, нулями и единицами. И сложность заключается в том, что число 0.1
в двоичной системе непредставимо. Это просто невозможно записать.
Всё далеко не так просто, но если кратко, то суть проблемы заключается именно в этом. Стоит понимать, что почти все современные и не только языки программирования считают с определенным допуском по точности. То есть не максимально точно, а с определенным её порогом. Слишком высокая точность вычислений приведет к тому, что языки будут совершать математические операции дольше. Поэтому используется та точность, которая будет удовлетворять нас по производительности, но, при этом, сведёт математические ошибки к минимально возможным. Эта самая точность по умному называется репрезентативностью.
Я советовал бы почитать что-нибудь ещё на эту тему в интернете, ведь тема интересная и в глубине далеко не такая простая, как может показаться на первый взгляд. К счастью, в интернете куча информации, особенно на английском языке.
Спасибо за прочтение, это важно для меня.
#theory
Pet-проекты и где они обитают
Почти год назад в этом канале я писал о pet-проектах. В том посте я рассказал совсем базовые вещи: что это такое и почему стоит попробовать. Сегодня хочу снова поднять эту тему немного в другом ключе.
Обучение программированию — это не только теория, на мой взгляд. Наоборот, хороший программист — это далеко не тот человек, кто использует правильные термины или знает абсолютно все микромоменты в технологии. Хороший программист — это человек творческий, способный решать задачи бизнеса быстро, дешево и качественно. Способный быстро адаптироваться к новым условиям и найти выход из ситуации, в которую попал впервые. Именно поэтому на многих собеседованиях вас просят писать код на обычной бумаге. Это заставляет вас работать в заведомо некомфортных условиях, и если вы в таких условиях пишете качественный код, то вы — хороший программист.
И как бы глубоки ваши теоретические знания ни были, без практических навыков вы не сможете показать хороший результат. А чтобы получить новые практические навыки и поэкспериментировать с технологиями, есть отличный вариант — pet-проекты. Замкнутый круг.
И в этом случае pet-проекты выступают прям панацеей для получения новых навыков. Идеи для таких проектов можно искать где угодно, но я бы посоветовал banda.works.
Вообще, это небольшая команда, которая делает открытые проекты для помощи в обучении и трудоустройстве новичкам в вебе. И сайт с pet-проектами — это один из проектов этой команды.
И сервис, на самом деле, находка. Там бесплатно размещены не только интересные проекты, но и некоторые вступительные испытания крупных компаний. Так что это отличный вариант изучить что-то действительно востребованное на рынке. Там, кстати, удобная сортировка по технологиям, так что если вы хотите написать проект на условном React, то сортировка делается в 1 клик.
Ещё тема трудоустройства поднимается в их телеграм канале: @bandaworks_bb.
Так же советую. Рекламу в этом канале я не продаю, так что этой рекомендации более чем можно доверять.
Примерно такие мысли на сегодня, спасибо за прочтение. Это важно для меня.
#blog #useful
Сделал на реакте блог, просто от безделья. Там некоторые посты с канала. Если кому-то интересно как канал мог бы выглядеть в форме сайта, то пощупать можно тут.
Страница проекта на guthub: markdown-github-blog
#blog
Function expression vs Function declaration.
В JavaScript объявить функцию можно по разному. Различают два способа, давайте рассмотрим их на примере функции сложения двух чисел:
Function declaration:
function sum(a, b) {
return a + b
}
const sum = function sum(a, b) { return a + b }
const sum = (a, b) => a + b
sum(2, 7) // 9
function sum(a, b) {
return a + b
}
sum(2, 7) // ReferenceError: sum is not defined
const sum = function sum(a, b) { return a + b }
Деструктуризация JavaScript
Как вы справляетесь с ситуацией, когда из объекта нужно сохранить определенную переменную?
Самым удобным способом является деструктуризация. Это синтаксис, когда мы в одну строку создаем несколько переменных из какого-либо объекта.
const json = {
name: "Denis",
surname: "Putnov",
age: 19,
email: "email@email.com",
adress: {
city: "Voronezh",
country: "Russia",
},
username: "grnbows"
}
const sayHi = (person) =>
console.log(`Hi ${person.name} from ${person.adress.country}`)
const sayHi = (person) => {
const {name, adress: {country}} = person
console.log(`Hi ${name} from ${country}`)
}
const sayHi = ({ name, adress: { country } }) =>
console.log(`Hi ${name} from ${country}`)
Сессия в унике негативно влияет на канал. Пост завтра в 17:00
Читать полностью…IIFE
Продолжим разбирать концепции JavaScript'а и сегодня быстро посмотрим на то, как использовать все преимущества блочной зоны видимости без let
и const
, только с помощью var
и небольшой хитрости.
В прошлом посте я уже рассказал о том что такое блочная область видимости, но иногда речь заходит о поддержке старых версий EcmaScript, поддержке старых браузеров ( что сейчас уже пусть и актуально, но не так сильно, как раньше ). В таких случаях мы не можем использовать let
и const
, а следовательно и блочная область видимости нам недоступна. В таких случаях используют IIFE.
IIFE — Immediately-invoked Function Expression — или мгновенно вызываемое функциональное выражение. Это определенный синтаксический прием, который позволяет сразу объявить и вызвать функцию в указанном месте. Таким образом мы создаем костыльный аналог блочной области видимости, который ограничено областью видимости этого функционального выражения. Тут рассмотрим пример.
Допустим, нам нужно проитерироваться по массиву и вывести его значения через какой-то промежуток времени:
var array = [1, 2, 3, 4, 5]
for (var i = 0; i < array.length; i++) {
setTimeout(() => {
console.log(array[i])
}, 500)
}
Казалось бы, все предельно просто и мы ожидаем вывод чисел от 1 до 5 последовательно через 500 миллисекунд. Но вот нет, всё не так просто. Какой бы вывод вы не ожидали, очень много людей тут делают ошибки.
На самом деле вывод такой:
undefined
undefined
undefined
undefined
undefined
Что? Почему? Всё из-за особенностей объявления переменной через var. Итерация проходит менее чем за 500мс. На моём ПК она проходит всего за 2мс. Значение переменной i
в начале последнего прохода достигает значения 4, а в конце прохода становится равной 5 ( т.к. выражение i++
выполняется после отрабатывания всего тела for
)
Функция setTimeout
никак не блокирует поток, поэтому мы быстро итерируемся, получаем i = 5
, а через еще 498мс обращаемся к array[5]
, но такого элемента нет, максимум 4, нумерация же с нуля. При этом с let
всё работает отлично
И когда нужно получить ожидаемый вывод, но нельзя использовать новый синтаксис, используется IIFE. Выглядят они так:
(function(локальное название переменных) {
тело функции
})(переменные на вход)
Перепишем вышеописанный пример с использованием IIFE:
for (var i = 0; i < array.length; i++) {
(function(i) {
setTimeout(() => {
console.log(array[i])
}, 500)
})(i)
}
Создаем функцию как блок, закидываем туда какие-то операции, оборачиваем в скобочки и сразу же вызываем с нужными параметрами. Таким образом создаем новую функциональную область видимости, которая нам и нужна.
В итоге получаем ожидаемый вывод:
1
2
3
4
5
Супер простой концепт, но много проблем решает. Вот мы и реализовали задачу в старом синтаксисе, ничего сложного.
И на этом всё, спасибо за прочтение. Если вам не лень, то поделитесь каналом с друзьями. Аудитория лишней точно не бывает. Люблю.
#javascript #web #theory
Итерирование по сущностям: map
Сегодня начну рассказывать еще и об интересных методах, которые почему-то знают не все. И для меня это было небольшим культурным шоком, потому что концепт достаточно простой, но почему-то крайне не распространен среди новичков.
Функция/метод map
реализована во многих ныне используемых языках программирования. Скажем так, реализация функций map
, reduce
и filter
дает языку хоть какое-то право называться функционально-поддерживаемым. Так вот, одна из этих функций — map
, используется для перебора массива. В JavaScript это метод класса Array.
a = [1, 2, 3].map(callback, context)
a = [1, 2, 3].map((element, index, array) => {
console.log(`${element} is the ${index} element of ${array}`)
})
// Output:
1 is the 0 element of 1,2,3
2 is the 1 element of 1,2,3
3 is the 2 element of 1,2,3
console.log(a)
// output
[ undefined, undefined, undefined ]
a = [1, 2, 3].map(element => element ** 2)
console.log(a)
// output
[1, 4, 9]
Замыкания
Изначально я и хотел обсудить такой концепт, как замыкания, потому что тема очень интересная и востребованная — почти каждое собеседование проходит с вопросом что такое замыкания и это очень важно понимать. Для понимания этой темы в начале лучше вникнуть в области видимости и разобраться что это всё таки такое.
Замыкание с точки зрения теории — это способность функции запомнить своё окружение (ссылки на переменные) в момент вызова. Это такой способ манипуляции областями видимости, который позволяет «замкнуть» переменную внутри тела функции. При помощи такой манипуляции мы можем расширить функционал обычных функций путём создания новых функций с замкнутыми в них переменными. На теории всё вообще не понятно, хотя я правда старался. Рассмотрим пример:
function sayHello(name) {
function wrapped() {
console.log(`Привет, ${name}`)
}
return wrapped
}
// создаем много функций на базе одной
const helloDenis = sayHello("Денис")
const helloKate = sayHello("Катя")
const helloMax = sayHello("Макс")
helloDenis() // Привет, Денис
helloKate() // Привет, Катя
helloMax() // Привет, Макс
sayHello
мы объявляем локальную функцию, которая остается доступной только внутри тела этой самой функции (из-за особенностей областей видимости). Возвращаем эту функцию. А у этой функции есть доступ к переменной name
. Значение переменной при вызове sayHello
замыкается, так как при каждом вызове функции sayHello
внутри нее создается своя локальная переменная name
, никак не зависящая от вызова этой функции снова. На практике должно быть понятнее.О переходе.
Обычный пост из серии блога, где я хочу объяснить почему на канале теперь будет JavaScript (не только он).
Я думаю, многим не понравится, что с Python я резко и без особых предпосылок перескочил на JavaScript. Как говорится, ничего не предвещало беды, но пришло откуда не ждали.
Я могу сказать, что Python был моим первым серьёзным языком программирования и я безумно рад, что это был именно он, не смотря на все проблемы этого языка. Я очень люблю Python до сих пор и считаю этот язык лучшим выбором для начала, но уже достаточно давно я стал заниматься именно JavaScript из-за собственного интереса или обстоятельств. Сначала я просто пытался изучить новый язык из интереса и ради развития кругозора, прошёл пару курсов, а потом как-то и сайтики нужно было пописать, да и просто более глубокий интерес развился, так что как-то закрутилось. Прям история любви.
JavaScript, конечно, отвратительный язык, с таким количеством проблем, число которых озвучить страшно. Но именно на этом стеке я знаю больше всего. На этой технологии я наиболее компетентен и именно на JavaScript я смогу выдать гораздо больше интересного и не очень контента.
Почему должно быть всё равно?
Большинство концептов, существующих в программировании, можно рассмотреть обособленно от конкретного языка. В современном мире различия не так критичны, поэтому огромная часть теории актуальна от языка к языку. Я не знаю Java или С#, но практически все книги по архитектуре приложений и тому подобным темам я прочитал с примерами на этих двух языках. И если отбросить всю предвзятую ненависть к JavaScript, которая присуща комьюнити сегодня, то на каком бы языке теория не была описана - при желании всё легко читается и понимается. Даже на JavaScript.
#blog
Что такое синхронный и асинхронный код.
Я пост написал, а он слишком большой, так что этот пост про асинхронщину - лишь часть будущей серии постов, скоро будет. Тут мы разберём синхронный и асинхронный код и сделаем это на примере великого и ужасного JavaScript, потому что я всё же выбрал этот язык как свою основную технологию уже давно, даже относительно создания канала. Я кое-как знаю Python, но больше не вижу смысла проталкивать это направление на канале. Итак, слишком много отступлений, переходим к делу.
Что же такое синхронный и асинхронный код в однопоточных языках (типа JavaScript или Python):
Синхронный код - код, который выполняет все описанные функции и алгоритмы последовательно. Если какая-то задача занимает слишком много времени, то весь процесс выполнений кода остановится и дождётся выполнения этой самой операции, и только после получения какого-либо результата пойдёт дальше. В каждый момент времени может выполняться только одна команда, обрабатываемая в единственном — главном потоке. Все остальные действия блокируются до окончания выполнения текущей команды.
Асинхронный код - это тот код, который не блокирует поток при выполнении операции и передаёт управление дальше. Все действия выполняются параллельно, а не последовательно. А если не останавливать поток, то чаще всего мы получим прирост в производительности (ну если сделаем всё правильно, конечно).
Но из-за асинхронного кода могут наблюдаться подобные варианты исполнения кода:
// code
setTimeout(() => {
console.log("Сообщение сразу")
}, 1500)
console.log("Сообщение через 1500мс")
// console out
Сообщение через 1500мс
Сообщение сразу