Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Слабка (==) проти суворої (===) рівності в JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Сувора рівність (`===`)** порівнює значення і тип без перетворень. **Слабка рівність (`==`)** спочатку перетворює операнди до спільного типу, а потім порівнює. ```javascript 5 === "5"; // false - різні типи 5 == "5"; // true - рядок стає числом null == undefined; // true - спеціальне правило ``` **Ключове:** використовуй `===` скрізь. Єдиний прийнятний виняток — `if (value == null)`, що ловить і `null`, і `undefined` одним рядком.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Сувора рівність (`===`)** перевіряє значення і тип без жодних перетворень. **Слабка рівність (`==`)** спочатку перетворює операнди до спільного типу, а потім порівнює результати. ## Теорія ### TL;DR - `===` — як підібрати взуття точно за розміром і кольором; `==` — як розтягнути його під будь-яку ногу - `===` не виконує жодних перетворень типів; `==` запускає алгоритм Abstract Equality Comparison - `5 === "5"` дає false; `5 == "5"` дає true (рядок стає числом) - `null == undefined` дає true за специфікацією; `null === undefined` — false - Правило: скрізь використовуй `===`; `==` прийнятна лише для перевірки `null/undefined` ### Короткий приклад ```javascript console.log(5 === 5); // true console.log(5 === "5"); // false - number vs string, без конвертації console.log(5 == "5"); // true - "5" перетворюється на 5 console.log(true === 1); // false - boolean vs number console.log(true == 1); // true - true перетворюється на 1 console.log(null == undefined); // true - спеціальне правило специфікації console.log(null === undefined);// false - різні типи ``` `===` зупиняється на перевірці типу. `==` продовжує і конвертує. ### Головна різниця `===` працює за алгоритмом SameValue: спочатку порівнює теги типів, потім значення. Без перетворень, без сюрпризів. `==` запускає Abstract Equality Comparison, який перетворює рядки на числа, булеві значення на числа (true в 1, false в 0) і викликає `valueOf`/`toString` для об'єктів. Саме через цей ланцюжок `[] == 0` дає true: `[]` викликає `toString()` і отримує `""`, а потім `""` перетворюється на `0` через ToNumber. ### Коли що використовувати - Будь-яке звичайне порівняння: використовуй `===` - Перевірка на `null` або `undefined` одночасно: `value == null` ловить обидва варіанти одним рядком - Порівняння введення користувача з числом після `parseInt`: явно через `===` - Застарілий код, де приведення типів задокументоване навмисно: `==` з коментарем ### Таблиця порівняння | Аспект | `===` (Сувора) | `==` (Слабка) | |---|---|---| | Перевірка типу | Так, тип + значення | Ні, спочатку конвертує | | Приведення типів | Відсутнє | Автоматичне (рядок в число тощо) | | Передбачуваність | Висока | Низька | | Продуктивність | Трохи швидше | Трохи повільніше | | `5 == "5"` | false | true | | `null == undefined` | false | true | | Коли використовувати | Всі порівняння | Тільки `value == null` | ### Як це працює всередині V8 реалізує `===` як пряме порівняння тегів типів із подальшою перевіркою значень. Ніяких алокацій, ніяких перетворень. Для `==` рушій запускає ToPrimitive для об'єктів (спочатку `valueOf`, потім `toString`), а потім ToNumber для рядків. Ланцюжок перетворень може складатися з трьох кроків перед тим, як отримати фінальний результат. ### Типові помилки **Використання `==` там, де очікується один конкретний тип:** ```javascript // Неправильно - "0" і [] теж відповідатимуть умові if (userInput == 0) { ... } // Правильно if (userInput === 0) { ... } ``` **Перевірка порожнього масиву через `==`:** ```javascript // Неправильно - ніколи не буде true, посилання різні if (data == []) processData(); // Правильно if (data.length === 0) processData(); ``` **`NaN` ніколи не дорівнює самому собі:** ```javascript console.log(NaN === NaN); // false console.log(NaN == NaN); // false - те саме правило // Правильна перевірка Number.isNaN(value); ``` **Умова циклу зі строковим введенням:** ```javascript // Неправильно - рядок "1" відповідає умові, цикл виконується несподівано while (count == 1) count--; // Правильно while (count === 1) count--; ``` ### Де зустрічається в реальному коді - React: `props.id === expectedId` у захисті компонентів - Express: `req.params.id === 'new'` в обробниках маршрутів - Node.js: `process.env.NODE_ENV === 'production'` - Redux: `action.type === types.FETCH_SUCCESS` - Правило ESLint `eqeqeq` автоматично примушує використовувати `===` у кодовій базі ### Питання на співбесіді **Q:** Чому `[] == 0` дає true? **A:** `[]` викликає `toString()` і отримує `""`, потім `""` перетворюється на `0` через ToNumber. Тому `[] == ""` і `"" == 0`, звідси `[] == 0` — true. **Q:** `null == undefined` — це true? Чому? **A:** Так, це спеціальний випадок в Abstract Equality Comparison за специфікацією. Тільки `null` і `undefined` дорівнюють одне одному через `==`; жодне з них не дорівнює `0`, `false` чи `""`. **Q:** `NaN === NaN` — false. Як перевірити на NaN? **A:** Використовуй `Number.isNaN(value)`. Трюк `x !== x` теж спрацює, бо NaN — єдине значення, що не дорівнює самому собі. `Object.is(value, NaN)` також варіант. **Q:** Чи є місце для `==` у продакшені? **A:** Один випадок: `if (value == null)` ловить і `null`, і `undefined` одним рядком. Деякі команди свідомо використовують цей патерн. В усьому іншому `===` — безпечний вибір за замовчуванням. **Q:** Що додає `Object.is()` порівняно з `===`? **A:** Два граничних випадки: `Object.is(NaN, NaN)` дає true (на відміну від `===`), і `Object.is(+0, -0)` дає false (на відміну від `===`). Для більшості коду `===` достатньо, але `Object.is` точно відповідає специфікації SameValue. ## Приклади ### Базова поведінка приведення типів ```javascript // Сувора рівність - типи повинні збігатися console.log(5 === 5); // true console.log(5 === "5"); // false console.log(false === 0); // false // Слабка рівність - приведення типів у дії console.log(5 == "5"); // true - рядок стає числом console.log(false == 0); // true - false стає 0 console.log("" == 0); // true - порожній рядок стає 0 console.log("0" == false); // true - обидва стають 0 ``` `==` порівнює без конвертації лише тоді, коли обидві сторони вже мають однаковий тип. ### Патерн у React-компоненті ```javascript function UserCard({ userId, isActive }) { // Сувора перевірка - "0" не сприймається як відсутній пропс if (userId === undefined) return <div>No user</div>; // Безпечна перевірка через == - ловить і null, і undefined if (isActive == null) return <div>Status unknown</div>; return <div>User {userId} is {isActive ? "active" : "inactive"}</div>; } // Патерн з process.env - завжди сувора рівність const isProd = process.env.NODE_ENV === "production"; ``` Я сам почав суворо дотримуватись `===` після того, як витратив час на відлагодження циклу, який виконувався зайвий раз: API повертав рядок `"1"` замість числа `1`. Без `===` це не видно одразу.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.