ЛУЧШИЙ САЙТ ДЛЯ ВЕБ-РАЗРАБОТЧИКОВ

JavaScript Учебник

JavaScript Старт Введение в JavaScript Справочники Редакторы кода Консоль разработчика Привет, Мир! Структура кода Строгий режим Переменные Типы данных Alert. Prompt. Confirm Преобразование типов Базовые Операторы Операторы сравнения If... Else Логические операторы Оператор объединения Циклы While и For Switch Базовые функции Функции-выражения Функции-стрелки Особенности JavaScript Дебаггинг в Chrome Стиль кода Комментарии Ниндзя-код Тестирование с Mocha Полифилы Объекты Копирование объектов Уборка мусора Методы объекта Конструктор, New Опциональная цепочка Тип данных Symbol Преобразование объектов Методы примитивов Числа Строки Массивы Методы массивов Перебираемые объекты Map и Set WeakMap и WeakSet Object.keys, values, entries Деструктурирующее присваивание Дата и время Формат JSON Рекурсия и стек Остаточные параметры и оператор расширения Замыкание Ключевое слово var Глобальный объект Объект функции, NFE Синтаксис "new Function" Планирование: setTimeout и setInterval Декораторы и переадресация вызова, call/apply Привязка контекста к функции Повторяем стрелочные функции Флаги и дескрипторы свойств Свойства - геттеры и сеттеры Прототипное наследование F.prototype Встроенные прототипы Методы прототипов Класс: базовый синтаксис Наследование классов Статические свойства и методы Приватные и защищённые методы и свойства Расширение встроенных классов Проверка класса: "instanceof" Примеси Обработка ошибок, "try..catch" Пользовательские ошибки Введение: кэлбэки Промисы Цепочка промисов Промисы: обработка ошибок Promise API Промисификация Микрозадачи Async/await Генераторы Асинхронные итераторы и генераторы Модули. Введение Экспорт и импорт Динамические импорты Proxy и Reflect Eval: выполнение строки кода Каррирование Побитовые операторы BigInt Intl: интернационализация в JavaScript

Браузер: документ, события, интерфейсы

Браузерное окружение, спецификации DOM-дерево Навигация по DOM-элементам Поиск: getElement*, querySelector* Свойства узлов: тип, тег и содержимое Атрибуты и свойства Изменение документа Стили и классы Размеры и прокрутка элементов Размеры и прокрутка окна Координаты Введение в браузерные события Всплытие и погружение Делегирование событий Действия браузера по умолчанию Генерация пользовательских событий Основы событий мыши Движение мыши: mouseover/out, mouseenter/leave Drag'n'Drop с событиями мыши Клавиатура: keydown и keyup События указателя Прокрутка Свойства и методы формы Фокусировка: focus/blur События: change, input, cut, copy, paste Отправка формы: событие и метод submit Страница: DOMContentLoaded, load, beforeunload, unload Скрипты: async, defer Загрузка ресурсов: onload и onerror MutationObserver: наблюдатель за изменениями Selection и Range Событийный цикл: микрозадачи и макрозадачи

JavaScript. Уроки для начинающих

JavaScript Базовые операторы, математика


Многие операторы сравнения известны нам из математики.

В JavaScript они записываются так:

  • Больше/меньше: a > b, a < b.
  • Больше/меньше или равно: a >= b, a <= b.
  • Равно: a == b. Обратите внимание, для сравнения используется двойной знак равенства ==. Один знак равенства a = b означает присваивание.
  • Не равно. В математике обозначается символом , но в JavaScript записывается как a != b.

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

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


Результат сравнения имеет логический тип

Все операторы сравнения возвращают значение логического типа:

  • true – означает «да», «верно», «истина».
  • false – означает «нет», «неверно», «ложь».

Например:

alert( 2 > 1 ); // true (верно)
alert( 2 == 1 ); // false (неверно)
alert( 2 != 1 ); // true (верно)

Результат сравнения можно присвоить переменной, как и любое значение:

let result = 5 > 4; // результат сравнения присваивается переменной result
alert( result ); // true

Сравнение строк

Чтобы определить, что одна строка больше другой, JavaScript использует «алфавитный» или «лексикографический» порядок.

Другими словами, строки сравниваются посимвольно.

Например:

alert( 'Я' > 'А' ); // true
alert( 'Коты' > 'Кода' ); // true
alert( 'Сонный' > 'Сон' ); // true

Алгоритм сравнения двух строк в JavaScript довольно прост:

  1. Сначала сравниваются первые символы строк.
  2. Если первый символ первой строки больше (меньше), чем первый символ второй, то первая строка больше (меньше) второй. Сравнение завершено.
  3. Если первые символы равны, то таким же образом сравниваются уже вторые символы строк.
  4. Сравнение продолжается, пока не закончится одна из строк.
  5. Если обе строки заканчиваются одновременно, то они равны. Иначе, большей считается более длинная строка.

В примерах выше сравнение 'Я' > 'А' завершится на первом шаге, тогда как строки 'Коты' и 'Кода' будут сравниваться посимвольно:

  1. К равна К.
  2. о равна о.
  3. т больше, чем д. На этом сравнение заканчивается. Первая строка больше.

Используется кодировка Unicode, а не обычный алфавит

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

Например, в JavaScript имеет значение регистр символов. Заглавная буква "A" не равна строчной "a". Какая же из них больше? Строчная "a". Почему? Потому что строчные буквы имеют больший код во внутренней таблице кодирования, которую использует JavaScript (Unicode). Мы ещё поговорим о внутреннем представлении строк и его влиянии в главе Строки.


Сравнение разных типов

При сравнении значений разных типов JavaScript приводит каждое из них к числу.

Например:

alert( '2' > 1 ); // true, строка '2' становится числом 2
alert( '01' == 1 ); // true, строка '01' становится числом 1

Логическое значение true становится 1, а false – 0.

Например:

alert( true == 1 ); // true
alert( false == 0 ); // true

Забавное следствие

Возможна следующая ситуация:

  • Два значения равны
  • Одно из них true как логическое значение, другое – false

Например:

let a = 0;
alert( Boolean(a) ); // false

let b = "0";
alert( Boolean(b) ); // true

alert(a == b); // true!

С точки зрения JavaScript, результат ожидаем. Равенство преобразует значения, используя числовое преобразование, поэтому "0" становится 0. В то время как явное преобразование с помощью Boolean использует другой набор правил.


Строгое сравнение

Использование обычного сравнения == может вызывать проблемы. Например, оно не отличает 0 от false:

alert( 0 == false ); // true

Та же проблема с пустой строкой:

alert( '' == false ); // true

Это происходит из-за того, что операнды разных типов преобразуются оператором == к числу. В итоге, и пустая строка, и false становятся нулём.


Как же тогда отличать 0 от false?

Оператор строгого равенства === проверяет равенство без приведения типов.

Другими словами, если a и b имеют разные типы, то проверка a === b немедленно возвращает false без попытки их преобразования.

Давайте проверим:

alert( 0 === false ); // false, так как сравниваются разные типы

Ещё есть оператор строгого неравенства !==, аналогичный !=.

Оператор строгого равенства дольше писать, но он делает код более очевидным и оставляет меньше места для ошибок.


Сравнение с null и undefined

Поведение null и undefined при сравнении с другими значениями — особое:

При строгом равенстве ===

Эти значения различны, так как различны их типы.

alert( null === undefined ); // false

При нестрогом равенстве ==

Эти значения равны друг другу и не равны никаким другим значениям. Это специальное правило языка.

alert( null == undefined ); // true

При использовании математических операторов и других операторов сравнения < > <= >=

Значения null/undefined преобразуются к числам: null становится 0, а undefinedNaN.

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


Странный результат сравнения null и 0

Сравним null с нулём:

alert( null > 0 ); // (1) false
alert( null == 0 ); // (2) false
alert( null >= 0 ); // (3) true

С точки зрения математики это странно. Результат последнего сравнения говорит о том, что "null больше или равно нулю", тогда результат одного из сравнений выше должен быть true, но они оба ложны.

Причина в том, что нестрогое равенство и сравнения < > <= >= работают по-разному. Сравнения преобразуют null в число, рассматривая его как 0. Поэтому выражение (3) null >= 0 истинно, а null > 0 ложно.

С другой стороны, для нестрогого равенства == значений undefined и null действует особое правило: эти значения ни к чему не приводятся, они равны друг другу и не равны ничему другому. Поэтому (2) null == 0 ложно.


Несравненное значение undefined

Значение undefined несравнимо с другими значениями:

alert( undefined > 0 ); // false (1)
alert( undefined < 0 ); // false (2)
alert( undefined == 0 ); // false (3)

Почему же сравнение undefined с нулём всегда ложно?

На это есть следующие причины:

  • Сравнения (1) и (2) возвращают false, потому что undefined преобразуется в NaN, а NaN – это специальное числовое значение, которое возвращает false при любых сравнениях.
  • Нестрогое равенство (3) возвращает false, потому что undefined равно только null, undefined и ничему больше.

Как избежать проблем в JavaScript?

Зачем мы рассмотрели все эти примеры? Должны ли мы постоянно помнить обо всех этих особенностях? Не обязательно. Со временем все они станут вам знакомы, но можно избежать проблем, если следовать надёжным правилам:

  • Относитесь очень осторожно к любому сравнению с null/undefined, кроме случаев строгого равенства ===.
  • Не используйте сравнения < > <= >= с переменными, которые могут принимать значения null/undefined, разве что вы полностью уверены в том, что делаете. Если переменная может принимать эти значения, то добавьте для них отдельные проверки.

Резюме

  • Операторы сравнения возвращают значения логического типа.
  • Строки сравниваются посимвольно в лексикографическом порядке.
  • Значения разных типов при сравнении приводятся к числу. Исключением является сравнение с помощью операторов строгого равенства/неравенства.
  • Значения null и undefined равны == друг другу и не равны любому другому значению.
  • Будьте осторожны при использовании операторов сравнений вроде > и < с переменными, которые могут принимать значения null/undefined. Хорошей идеей будет сделать отдельную проверку на null/undefined.

✅ Задача

Операторы сравнения

Каким будет результат этих выражений?

5 > 4
"ананас" > "яблоко"
"2" > "12"
undefined == null
undefined === null
null == "\n0\n"
null === +"\n0\n"
5 > 4 → true
"ананас" > "яблоко" → false
"2" > "12" → true
undefined == null → true
undefined === null → false
null == "\n0\n" → false
null === +"\n0\n" → false

Разъяснения:

  1. Очевидно, true.
  2. Используется посимвольное сравнение, поэтому false. "а" меньше, чем "я".
  3. Снова посимвольное сравнение. Первый символ первой строки "2" больше, чем первый символ второй "1".
  4. Специальный случай. Значения null и undefined равны только друг другу при нестрогом сравнении.
  5. Строгое сравнение разных типов, поэтому false.
  6. Аналогично (4), null равен только undefined.
  7. Строгое сравнение разных типов.