Заблуждения о языке Javascript · Xam React CoE

Разоблачение распространенных заблуждений, ошибочных убеждений и неправильного использования языка NodeJS/Javascript/Typescript.

📢 Целевая аудитория

Инженеры-программисты NodeJS/Javascript/Typescript и разработчики js/ts утилит и плагинов для линтинга.

ℹ️ Введение

Слишком часто я вижу неправильное использование языка js/ts, основанное на одном или нескольких из:

  • Непонимание языка.
  • Введено в заблуждение чрезмерно самоуверенными разработчиками, которые неправильно понимают язык.
  • Плохо обоснованные стандарты кодирования или настройки библиотеки linting по умолчанию (обычно предназначены для людей с минимальным пониманием языка).

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

🤔 Обоснование

Причины понимать язык и правильно его использовать включают в себя:

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

❌ Заблуждения

👎 Двойная кавычка должна быть предпочтительнее, чем одинарная кавычка

Начнем с простого и очевидного.

В js/ts символы двойной кавычки и одинарной кавычки эквивалентны, поэтому можно использовать любой из них.

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

  1. Эффективность:
    для ввода одинарной кавычки требуется 1 нажатие клавиши, а для ввода двойной кавычки — 2 нажатия клавиши.
    Символы кавычек часто вводятся в js/ts.
    Использование одинарных кавычек значительно сокращает количество нажатий клавиш, которые потребуются в ходе вашей карьеры разработчика?
  2. Удобство:
    Двойные кавычки появляются в строках чаще, чем одиночные символы, и особенно в HTML (атрибутах), для рендеринга которых часто используется js/ts.
    Таким образом, инкапсуляция строк в Одинарные кавычки предотвращают необходимость избегать двойных кавычек.

Итак, должен ли я строго применять только одинарные кавычки?

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

По этой причине я рекомендую разрешить любой из них и предпочесть одиночный.

Как настроить это в eslintrc.js

quotes: ['error', 'single', {avoidEscape: true}]

👎 == никогда нельзя разрешать, используйте только ===

Нет, применение Tripple Equals (строгое равенство) только отключает замечательную языковую функцию.

В js/ts операторы равенства == и != проверяют, равны ли (или не равны) 2 значения в рамках определенного набора правил.

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

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

👍Некоторые практические правила:

  • 'this string' не делает == ничего, кроме 'this string'
  • undefined делает == null
  • '42' делает == 42
  • Чаще всего подходит Равенство == или Истина/Ложь (поясняется ниже).

Итак, где == полезен?

Если вы считаете null и undefined одинаковыми (ПРИМЕЧАНИЕ: вместо этого вам может понадобиться Falsy или Truthy):

const val: undefined|null = undefined;
if (val == null)
    console.log('val is undefined or null');

Если вы работаете с числами, и значения могут храниться в виде строк, например. если вы загрузили их из ключей объекта, файла, JSON, вызова API или какого-либо анализа:

const num = 42;
const strNum = '42';
if (num == strNum)
    console.log('num == strNum');
// you could do a type conversion and type check but its overkill
if (num === +strNum)
    console.log('num === +strNum');

Если вы знаете, что одна из переменных является строкой:

const val: any = aVarOfUnknownTypeAndValue;
// no need for type check as only 'Hi' is equal
const isStrHi = val == 'Hi';
// no need for type check as only 'string' is equal
const isStr = 'string' == typeof aVarOfUnknownTypeAndValue;

Если вы работаете со ссылками на объекты:

const objA = {a: 1};
const refA = objA;
const objB = {...objA};
if (objA == refA)
    console.log('objA == refA');
if (objA != objB)
    console.log('objA != objB');

ПРИМЕЧАНИЕ: для глубокого сравнения значений объектов вам понадобится что-то вроде lodash.isEqual();

А где === пригодится?

Операторы строгого равенства === и !== имеют гораздо меньше вариантов использования, и вы обнаружите, что вам редко нужно их использовать.

Тем не менее, у него, безусловно, есть свои приложения…

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

const val: undefined|null = funcThatReturnsUndefinedOrNull();
if (val === null)
    console.log('val is null');
else
    console.log('val is undefined');

В случае, когда вы не хотите, чтобы строковый номер считался таким же, как число:

const num = 42;
const strNum = '42';
if (num !== strNum)
    console.log('num !== strNum');

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

  • Переменные являются примитивными типами данных, и
  • Значение и тип каждой переменной неизвестны, и
  • Номера строк не должны считаться равными их эквивалентным числам (‘42’ считается не равным 42), и
  • undefined следует считать не равным null.
type Primitive = undefined|null|boolean|string|number|symbol;
const left: Primitive = valueA;
const right: Primitive = valueB;
const same = left === right;

Сравнительная таблица

Как отключить принудительные проверки строгого равенства в eslintrc.js

eqeqeq: 0

👎 Truthy и Falsy не следует использовать для проверки состояния.

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

if (thisMustBeABoolean) // X Wrong
    doSomething(); 
// and
thisMustAlsoBeABoolean ? go() : stop(); // X Wrong

Truthy и Falsy — отличные возможности языка Javascript, если вы изучали язык и понимаете их.

На самом деле, в большинстве тестов условий Истинная/Ложная проверка будет более подходящей, чем проверки Равенства или Строгого Равенства.

👍Практические правила:

  • Спросите себя: «Чего я пытаюсь достичь с помощью проверки состояния?»
  • Спросите, какие значения может содержать переменная и как каждое из них может быть оценено.

Пример

Вот один из многих примеров, когда предпочтение отдается правде/лжи…

Случай: Вы хотите сообщить о сообщении, если у вас есть сообщение, о котором нужно сообщить:

const message: undefined|null|string = getError();
// WRONG: message may be null or ''
if ('undefined' != typeof message)
    console.error(message);
// WRONG: message may be ''
if ('string' == typeof message)
    console.error(message);
// WRONG: message may be null or ''
if (message === undefined)
    console.error(message);
// WRONG: message may be ''
if (message == undefined)
    console.error(message);
// OK but complete overkill when js provides truthy/falsy
if ('string' == typeof message && message.length > 0)
    console.error(message);
// CORRECT
if (message)
    console.error(message);

Как убедиться, что Truthy/Falsy работает в .eslintrc.js

'@typescript-eslint/strict-boolean-expressions': 0

👎 Для отступов следует использовать пробелы, а не вкладки

Еще одно не продуманное представление.

Есть несколько веских аргументов в пользу того, почему отступы табуляции предпочтительнее пробелов:

  1. Эффективность разработчика:
    Таблица состоит из одного символа, отступ пробела — 2, 4 или 8.
    Таким образом, набор текста или перемещение (с помощью клавиш со стрелками) отступа пробела — это дополнительные нажатия клавиш.
  2. Дисковое пространство:
    Размер файла (предварительная минимизация) больше, он содержит в 2, 4 или 8 раз больше символов отступа.
  3. Загрузка процессора.
    В вашей среде IDE, компиляторе Typescript и синтаксическом анализаторе javascript приходится обрабатывать больше символов и, следовательно, больше нагрузки.

Вы можете возразить, что ваша IDE позаботится об отступах. Вы нажимаете Tab, и он рисует для вас 2, 4 или 8 пробелов (в зависимости от ваших настроек). И если вы никогда не редактируете код вне настроенной вами IDE, и вас не смущает дополнительная нагрузка на вашу IDE или компьютер, то это не имеет значения, верно? Я согласен, если вы нажмете вкладку и получите 2/4/8 пробелов, то это действительно не имеет значения, так что вы можете просто нарисовать вкладку и, таким образом, уменьшить размер файла и нагрузку на процессор в вашей среде IDE, компиляторе ts, и парсер js. Если это не имеет значения, то зачем без необходимости преобразовывать вкладки в пробелы?

Я обнаруживаю, что пишу и/или перемещаюсь по коду вне моего редактора в нескольких сценариях:

  • В отчетах об ошибках/логах
  • Онлайн-редакторы как песочницы
  • Я часто подключаюсь к серверу по ssh для отладки кода с помощью nano или vim.
  • Иногда я делюсь кодом в MS Teams, Skype или других средствах совместной работы.

Как сделать отступ табуляции в eslintrc.js

indent: ['error', 'tab']

👎 Всегда требуйте фигурные скобки вокруг блоков

В Javascript, если условие содержит однострочный код, фигурные скобки можно опустить, например:

if (logged)
    route('/home');
else
    route('/login');
// and
for (let val of vals)
    doSomething(val);

Во многих современных js/ts-приложениях это отключено. Предположительно, потому что это менее читабельно.
Я полагаю, что разработчики Python — например — не согласятся.
Мне бы хотелось увидеть опрос, в котором спрашивали, кому труднее читать вышеизложенное, чем:

if (logged) {
    route('/home');
}
else {
    route('/login');
}
// and
for (let val of vals) {
    doSomething(val);
}

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

Зачем разрешать опускать фигурные скобки там, где это применимо?

  • Меньше нажатий клавиш
  • Меньше ненужных символов и размера файла
  • Лучшая читабельность (в зависимости от того, кого вы спросите)

Как отключить использование фигурных скобок в eslintrc.js

'prettier/prettier': 0,
curly: 0,

👎 Всегда строго применяйте правила синтаксиса/линтинга для разработчиков

Все это поднимает вопрос: должен ли я применять к разработчикам строгие и самоуверенные синтаксические правила или нет?

Как я могу это сказать?

  1. eslint, tslint и большинство современных утилит проверки линтера или синтаксиса поддерживают:
    - автоматическое форматирование кода
    - форматирование кода для каждого дистрибутива или среды
    Таким образом, в настоящее время нет необходимости применять правила форматирования во время разработки, их можно добавить позже или в любое время, во время сборки, во время развертывания, перед доставкой клиенту или когда угодно.
  2. Каждый проект js/ts, как правило, имеет свой собственный строгий набор правил синтаксиса/линтинга, обычно основанный исключительно на личном мнении/предпочтении того, кто создавал кодовую базу.
    Итак, каждый раз, когда разработчики перемещаются между проектами, нам нужно учиться и адаптироваться к новым предпочтениям.
    Это замедляет работу, и мы часто тратим слишком много времени на рефакторинг кода, чтобы удовлетворить линтер.
  3. Разработчики работают быстрее и удобнее всего в предпочитаемых нами средах и с использованием наиболее часто используемого синтаксиса.
    И в большинстве проектов каждый разработчик работает над разными функциями поставки и, следовательно, над разными разделами кодовой базы.
    Вся причина все линтинговые войны ведутся из-за того, что у разработчиков есть свои личные предпочтения и мнения.
    Если вы уберете принудительное применение одного предпочтения разработчиков ко всем разработчикам и просто позволите им работать предпочитаемым ими способом, то у вас будут более счастливые и более эффективные разработчики.
  4. Когда вы ослабите правила линтинга, у вас будет меньше споров (извините, споров) по поводу синтаксиса в PR-обзорах. Поскольку, когда каждый член команды понимает, что каждый работает в соответствии со своими собственными предпочтениями синтаксиса, а код будет переформатирован позже, нет необходимости выбирать стили синтаксиса.
    Это дает больше времени для выявления потенциальных проблем, а также культивирование культуры принятия различий друг друга.

Итак, на что это похоже?

Существует несколько способов определения и управления правилами линтинга для каждой сборки или среды. Есть даже пакеты. Однако в самой простой форме вы можете:

  1. Настройте свой проект .eslintrc.* с минимальными ограничениями.
    Например, вы можете разрешить отступ табуляции или пробела для каждого файла.
  2. Создайте второй eslintrc, например, release.eslint.js с полными/строгими правилами форматирования в соответствии с предпочтениями клиента или владельца продукта.
  3. Тогда ваши сценарии package.json будут выглядеть примерно так:
  "scripts": {
        // ... other commands here
        "lint": "eslint --ext .ts,.tsx ./src",
        "lint:format": "eslint --fix --ext .ts,.tsx ./src",
        "lint:format-release": "eslint -c ./release.eslint.js --fix --ext .ts,.tsx ./src"
    },

Теперь просто извлеките ветку и запустите npm run lint:format-release, если вы хотите развернуть выпуск кодовой базы для своего клиента.

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

👏 Престижность

Следующие люди и организации пожертвовали своим временем и ресурсами, чтобы внести свой вклад в эту публикацию: