21 вересня 2023 р.

Оператори порівняння

Багато з операторів порівняння нам відомі з математики.

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

  • Більше/менше: a > b, a < b.
  • Більше/менше або дорівнює: a >= b, a <= b.
  • Дорівнює: a == b. Зверніть увагу, для порівняння потрібно використовувати два знаки рівності ==. Один знак рівності a = b означав би присвоєння.
  • Не дорівнює: в математиці позначається символом , проте в JavaScript записується як a != b.

В цьому розділі ми вивчимо різні типи порівнянь, дізнаємось, як JavaScript їх виконує, та розглянемо важливі особливості.

В кінці ви знайдете корисні поради, як уникати специфічних “примх” 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

Алгоритм порівняння рядків досить простий:

  1. Порівнюються перші символи обох рядків.
  2. Якщо перший символ першого рядка більший (менший) за перший символ другого рядка, то перший рядок більший (менший) за другий. Порівняння закінчено.
  3. В іншому випадку, якщо перші символи обох рядків рівні, то таким самим чином порівнюються вже другі символи рядків.
  4. Порівняння продовжується до того часу, доки не закінчиться один з рядків.
  5. Якщо два рядки закінчуються одночасно, то вони рівні. Інакше, довший рядок вважатиметься більшим.

В прикладах вище, порівняння 'Я' > 'А' завершиться на першому кроці.

Проте друге порівняння слів 'Соки' і 'Сода' буде виконуватися посимвольно:

  1. С дорівнює С.
  2. о дорівнює о.
  3. к більше ніж д. На цьому кроці порівнювання закінчується. Перший рядок більший.
Використовується кодування Unicode, а не справжній алфавіт

Такий алгоритм порівняння схожий на алгоритм сортування, який використовується в словниках і телефонних довідниках, проте вони не зовсім однакові.

Наприклад, в JavaScript має значення регістр символів. Велика буква "А" не рівна маленькій "а". Але яка з них більше? Маленька буква "а". Чому? Тому що маленькі букви мають більший код у внутрішній таблиці кодування, яку використовує JavaScript (Unicode). Ми розглянемо особливості і наслідки цього кодування в розділі Рядки.

Порівняння різних типів

Коли порівнюються значення різних типів, JavaScript конвертує ці значення в числа.

Наприклад:

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

Логічне значення true стає 1, а false0.

Наприклад:

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, тоді як undefined стає NaN.

Тепер глянемо, які кумедні речі трапляються, коли ми застосовуємо ці правила. І, що більш важливо, як уникнути помилок під час їхнього використання.

Дивний результат порівняння null і 0

Порівняємо null з нулем:

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

З погляду математики це дивно. Результат останнього порівняння показує, що "null більше або дорівнює нулю", в такому випадку результат одного з порівнянь вище повинен бути true, але вони обидва false.

Причина в тому, що нестроге порівняння == і порівняння > < >= <= працюють по-різному. Останні оператори конвертують null в число, розглядаючи його як 0. Ось чому вираз (3) null >= 0 дає true, а вираз (1) null > 0false.

З іншого боку, для нестрогого порівняння == значень undefined і null діє окреме правило: ці значення не перетворюються на інші типи, вони рівні один одному і не рівні будь-чому іншому. Ось чому вираз (2) null == 0 повертає результат false.

Не порівнюйте значення undefined

Значення undefined не має порівнюватись з іншими значеннями:

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

Чому тоді порівняння undefined з нулем завжди повертає false?

Ми отримуємо такі результати, тому що:

  • Порівняння (1) і (2) повертає false, тому що undefined під час порівняння з “не null” значеннями завжди конвертується в NaN, а NaN — це спеціальне числове значення, яке завжди повертає false під час будь-яких порівнянь.
  • Нестроге порівняння (3) повертає false, тому що undefined рівне тільки null, undefined і жодним іншим значенням.

Як уникати проблем

Чому ми переглядали ці приклади? Чи повинні ми постійно пам’ятати про всі ці особливості? Не обов’язково. З часом всі ці заплутані правила стануть для вас знайомими, але можна уникнути проблем, якщо дотримуватися надійних правил:

  • Будьте пильні під час порівняння будь-якого значення з undefined/null, за винятком строгого порівняння ===.
  • Не використовуйте порівняння >= > < <= зі змінними, які можуть приймати значення null/undefined, хіба що ви цілком впевнені в тому, що робите. Якщо змінна може приймати ці значення, то додайте для них окремі перевірки.

Підсумки

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

Завдання

важливість: 5

Який буде результат цих виразів?

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. Очевидно, 5 більше за 4. true.
  2. Посимвольне порівняння, тому false. "а" менше за "я".
  3. Знову посимвольне порівняння. Перший символ рядка "2" більший за перший символ другого рядка — "1".
  4. Спеціальний випадок. Значення null і undefined рівні лише один одному під час нестрогого порівняння.
  5. Строге порівняння різних типів, тому false.
  6. Аналогічно, як в кроці (4), null дорівнює лише undefined.
  7. Строге порівняння різних типів.
Навчальна карта

Коментарі

прочитайте це, перш ніж коментувати…
  • Якщо у вас є пропозиції, щодо покращення підручника, будь ласка, створіть обговорення на GitHub або одразу створіть запит на злиття зі змінами.
  • Якщо ви не можете зрозуміти щось у статті, спробуйте покращити її, будь ласка.
  • Щоб вставити код, використовуйте тег <code>, для кількох рядків – обгорніть їх тегом <pre>, для понад 10 рядків – використовуйте пісочницю (plnkr, jsbin, codepen…)