Дэн Щербаков ⚛️
96 subscribers
20 photos
49 links
Канал для фронтенд-разработчиков о том, как развиваться и увеличивать зарплату.

Senior Frontend Developer с 6 годами опыта. За этот период увеличил зарплату почти в 7 раз.

Начинайте тут: https://yangx.top/code_lab/280
加入频道
let z = {
misc: 5,
gett: function() {
return console.log( this.misc );
}
}

/*

Что, по шагам, делает функция bind?
1. принимает аргументы: внешнюю функцию и контекст.
2. возвращает функцию...
3. ...которая возвращает результат вызова внешней функции с привязкой контекста.
*/

function bind(func, context) {
return function() {
return func.apply(context, arguments);
}
}

setTimeout( bind(z.gett, z), 1000)

Что происходит здесь?

В setTimeout объявляется два аргумента. Аргумент - это, фактически, запись в переменную без её объявления.
Если передать в setTimeout функцию, не указывая контекст, она будет записана как переменная-аргумент - и потеряет контест (this).

Можно сказать, функция bind создаёт конструкцию вида:
var argument = function() {
return myFunction.apply(myContext, arguments);
}

Иначе говоря, первым аргументом setTimeout будет результат вызова myFunction в фиксированном контексте.

Встроенный метод .bind работает аналогично, но ему хватает и одного аргумента.
Про Git:

git status = git st - команда проверяет статус репозитория (нет ли чего незакоммиченного).
Если сделаны нежелательные изменения, но еще не закоммичены, на этой стадии можно откатить их командой checkout.
Гит выведет подсказку о доступных на стадии командах.

git add - команда интексации изменений. На этой стадии их тоже можно откатить - гит вновь подскажет команду, если ввести git status.
Подсказка: git add с ключом —all проиндексирует все измененные файлы.

Стадия индексации нужна для гибкости работы.

При попадании в VIM по команде commit не следует паниковать. Просто вводим в первую строку описание коммита, жмем ECS, вводим :wq - и попадём назад в командную строку.

Бинды команд для Гит делаются так:
git config --global alias.shortcut full command
Например, у меня git checkout установлена как git ch.
Команда cat выводит в консоль содержимое файла.
Чтобы откатить содержимое файла после коммитов, нужно:
1. Вывести с помощью git log историю коммитов
2. Набрать git ch <хеш нужной стадии> (очень поможет установка сокращенных хешей)
3. Набрать git ch master
Здесь проявляется важность комментирования: чем подробнее и понятнее будет описание коммитов, чем чаще они будут делаться, тем яснее, к какой стадии создания программы удобнее вернуться.
https://githowto.com/ru/aliases - как сделать сокращенные хеши и многое другое. И вообще курс полезный!
Простейший план работы с Git:
- Создается ветка продакшна (по умолчанию "master");
- В течение работы выбираются опорные точки, с которых хотели бы вводить экспериментальный код. Их роль играют коммиты;
- От опорных точек создаются новые ветки с помощью branch;
- По необходимости ответвляемся и от этих веток. Больше бранчей богу бранчей!
- Если экспериментальный код работает корректно, ветка сливается с master;
- Master пушится в удаленный репозиторий.
Некоторые сущности Git и полезные приемы:

- Большинство команд зависимо от контекста. Например:
git branch — выводит все текущие ветки;
git branch new-branch — создает новую ветку

- Не обязательно последовательно индексировать и коммитить изменения. Достаточно ввести команду:
git commit -a -m 'commentary'
А лучше добавить алиас и пользоваться шорткатом. Например, вместо предыдущей команды я пишу:
git com

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

- Чтобы не париться с VIM, желательно заменить редактор по-умолчанию на свой. Гуглим "Git редактор по-умолчанию".

- Основные команды по работе с ветками:
- merge
- cherry-pike
- rebase
- pull (в сущности, автоматический merge)
Различаются они гибкостью настроек цепочки коммитов. Например, git rebase -i позволяет одновременно видеть список коммитов и переставлять их в дереве.

- Простой алгоритм слияния веток:
1. git commit -a -m 'start commit'
2. git branch new-branch
3. git checkout new-branch
4. git commit -a -m 'experimental code'
5. git checkout master
6. git merge new-branch

- Команда tag - лучший друг и помощник. Перемещаться по дереву удобнее всего именно с её помощью - проще запомнить тег версии, чем даже шесть символов хеша.
Оценка сложности алгоритмов

Есть три шкалы оценки сложности алгоритмов: О-большое, Омега-большое и Тета-большое. Чаще всего используются первые два:

1. О-большое - производительность алгоритма в худшем случае.
2. Омега-большое - производительность в лучшем случае.

Запись O(n) означает, что алгоритм потребует количество единичных действий, состоящее из константы О и числа n - например, количества элементов массива.

О(n) - линейная сложность алгоритма. То есть, в худшем случае, алгоритм потребует n действий.
O(n2) - сложность, при которой потребуется n*n операций. Это откровенно низкая производительность.
O(lg n) - сложность, обозначаемая логарифмом от n. Это очень быстро. Например, для массива более чем из миллиона элементов потребуется всего 20 операций.

В оценке О-большого опускаются побочные множители. Самое главное - количество операций над структурой данных.
Автотесты в JS

По-хорошему, разработка должна начинаться с BDD-документации. Это значит, что перед написанием кода мы пишем спецификацию, в которой опеределяем возможные результаты работы кода, и пишем его, подстраивая под них. Если код проходит тестирование в пограничных условиях - значит, всё замечательно.

Автотесты делают с помощью фреймворков. Самые популярные - Чай и Мока.
Они работают как NPM-модули, но могут и подключаться через браузер.

Простой модуль тестов через Моку состоит из трёх вложенных блоков:
- describe(string, callback())
- it(string, callback()
- assert.test(arg,[args])

Describe - блок для группировки тестов. Аргумент string - название блока, ничего более.
It - обертка конкретного теста. Первый аргумент - строка описания, что код должен делать при условиях, описанных тестом: it('should return false when...').
Assert - обращение к библиотеке функций, которая занимается непосредственно анализом результатов. У assert есть аналоги, и внутри assert есть множество разных методов. Здесь указан абстрактный метод "assert.test", идентичный настоящему "equal". Метод "equal" ожидаемо сравнивает первый аргумент со вторым. Осторожно! Метод использует нестрогое сравнение!

Другие методы assert:
https://nodejs.org/api/assert.html
Элементарная математика

- Умножение - это совокупность тактов над каким-либо числом. Например, 6 * 3 = 6 + 6 + 6.
- Операцию выше можно назвать представлением. Представление - это описание числа как результата действий над другими числами. 18 = 6 * 3, 18 = 6 + 6 + 6, и 6 * 3 = 6 + 6 + 6.
- Разряд цифры - это ее позиция в числе. Возьмём 1024. В его разряде единиц - 4, в разряде десятков - 2, сотен - 0, тысяч - 1. Разряд говорит, сколько единиц, десятков, сотен, тысяч... и т.д. входят в число. Значением разряда могут быть только числа от 0 до 9, не считая дробей.
- Группировка чисел - это их представление как количества разрядных элементов. Скажем, 1024 = (100 * 10) + (10 * 2) * 4. Или 1000 + 20 + 4.

() => Разряды можно использовать для быстрого сложения больших чисел:

623 + 2422 = 2 + (6+4) + (2+2) + (2+3) = 3045.

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

Формально, такой способ перебрасывания лишних разрядов применяет для работы с числами представление их как групп разрядов. Применяется всё, что бысло описано выше.

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

756-699 = (6-6)+(14-9)+(16-9)=0+5+7=57.

() => Один из методов быстрого вычитания из чисел с большим количеством нулей на конце - вычитание единицы из таких чисел, затем классическое вычитание, затем прибавление единицы.

() => Если записать алгоритмически (на псевдо-JS) умножение на числа из первого разряда, равного 1, и остальными - равными 0, оно будет выглядеть так:
26 + 100 = 26.concat(00).
То есть мы просто переписываем нули из множителя во множимое. Или наоборот.
() => Алгоритм умножения многоразрядного числа на одноразрядное:
1. Умножаем значение разряда единиц множимого на множитель.
2. Если результат - многозначное число, пишем в результат его единицы, а значение разряда десятка перекидываем на следующий разряд множимого.
3. Умножаем следующий разряд.
4. Прибавляем к результату перекинутое значение в качестве единиц, записываем получившиеся единицы, а "лишний" разряд снова перебрасываем на следующий.
4. Повторяем, пока во множимом не кончатся числа. Последний "лишний" разряд записываем крайним слева.
Методы элементарной математики - образцы оптимизации алгоритмов. Например, метод округления делимого и делителя в делении многозначных чисел значительно сокращает количество проверок частного. Мы сразу берем наиболее вероятное частное, проверяем, умножая его на делитель и сверяя с делимым, и по результату проверки увеличиваем/уменьшаем на один такт.

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

1. Сложение/умножение:
1.1. Сочетательный закон:
a +* b = b + a
1.2. Переместительный:
a +* b +* c = (a +* b) +* c = a +* (b +* c)

2. Умножение:
2.1. Распределительный закон:
(a + b) * c = a * c + b * c

Практический пример последнего:
6 * (3 + 6) =
6 * 9
или
18 + 36

Работает он и с разностью.
- Делитель - это число, на которое число делится без остатка.
В делители любого положительного числа больше ноля обычно входят 1 и само число:
12:1=12
12:12=1
- Кратное числа - это число, которое делится на взятое нами число без остатка. Например, 10 - кратное 5.

Это интересно: кратных у любого числа - бесконечно много.

() => Алгоритмы поиска признаков делимости:

- на десять:
num[last] === 0 && num >= 10

- на пять и два:
см. выше.

- на пять:
num[last] === 5 && num > 0

- на три:
(num[0] + num[1] + ... + num[last]) % 3 === 0

- на девять:
(num[0] + num[1] + ... + num[last]) % 9 === 0
() => Алгоритм поиска всех делителей:

0. Простые множители: 2, 3, 5, 7.
1. Проверяем, делится ли число на наименьший простой множитель. Если нет, берем следующий.
2. Найдя подошедший, записываем его и делим на него число.
3. Повторяем, пока число не достигнет 1.
4. Удаляем повторяющиеся более двух раз.
5. Перемножаем между собой: как по два, так и большими порциями.
6. Получившиеся числа записываем в таблицу делителей.
- НОД - это наибольший общий делитель двух чисел. Запись:
НОД(а, b)

() => Алгоритмы поиска НОД:

1. Перебор:
- получаем все делители a
- затем b
- сравниваем, пока не найдём наибольшее число, повторяющееся в обеих последовательностях.

2. Перемножение общих делителей:
- раскладываем два числа на простые множители
- находим общие
- перемножаем
- наибольшее полученное число будет НОД

3. Вычеркивание:

- раскладываем на простые множители
- вычеркиваем из последовательности все множители, которые не повторяются, пока последовательности не станут идентичными
- перемножаем оставшиеся множители
- НОК - это наименьшее общее кратное. Иначе говоря - наименьшее число, которое нацело делится на a и b. Есть три алгоритма его поиска, которые проще загуглить, чем переписывать.
Дроби бывают правильными и неправильными.

Правильные - те, у которых числитель (знак сверху) больше знаменателя (снизу).
Остальные - неправильные.

Из неправильных можно выделить целое.
Для 2|2 целое = 1.
Для 17|3 = 17 / 3 = 5 целых 2|3.

Смешанное число - целое с дробью - можно представить как неправильную дробь. Для этого умножим целое на знаменатель и прибавим числитель. Вот формула:
Два свойства дробей:
1. Если умножить числитель и знаменатель на одно и то же число, значение дроби не изменится. Это число называется дополнительным множителем.
2. Большинство дробей можно сократить. Для этого находим НОД для обоих и делим на него. Результатом станет сокращенная дробь.
Дроби из простых чисел сократить, очеивдно, нельзя.