Чи замислювались ви, чому вираз 0 == [] в JavaScript дає результат true? Якщо ви, як і більшість розробників, то ця на перший погляд дивна порівняння може вас здивувати. Але не хвилюйтесь — це не магія, а типове приведення типів у JavaScript, і настав час розібратись!
Детальний розбір типового приведення типів в JavaScript
В JavaScript оператор == відомий як оператор ненадійного порівняння (loose equality), що означає, що він не просто порівнює значення напряму. Замість цього він намагається перетворити значення з обох сторін у спільний тип перед тим, як порівняти їх. Цей процес називається приведенням типів (type coercion), і це одна з причин, чому JavaScript може бути водночас потужним і складним для розуміння.
Коли ви порівнюєте 0 == [], JavaScript повинен перетворити обидва операнди в один тип перед тим, як здійснити порівняння. Давайте розглянемо цей процес:
0 == []
- Приведення
[](порожній масив): Спочатку JavaScript дивиться на масив[]. Оскільки масив є об'єктом, його неможливо порівняти безпосередньо з числом. JavaScript намагається перетворити масив у примітивне значення за допомогою алгоритмуToPrimitive. - Перетворення
[]в рядок: У JavaScript, коли об'єкт (наприклад, масив) приводиться до примітиву, він зазвичай перетворюється на рядок. Рядкове представлення порожнього масиву[]— це просто порожній рядок"". - Порівняння
0 == "": Тепер, коли масив[]був перетворений на порожній рядок"", порівняння відбувається між0і"". JavaScript продовжує процес приведення типів і перетворює порожній рядок""у число0. - Кінцеве порівняння: Тепер, коли обидва боки порівняння є числами (
0 == 0), JavaScript оцінює вираз якtrue.
Розуміння приведення типів
Ця поведінка може здатися дивною на перший погляд, але це повністю відповідає правилам ненадійного порівняння в JavaScript. Ось короткий огляд того, як JavaScript обробляє приведення типів у таких випадках:
- Об'єкти в примітиви: Коли об'єкти (наприклад, масиви або функції) беруть участь у порівнянні, JavaScript намагається перетворити їх у примітивні значення. Масиви перетворюються в рядки, викликаючи їх метод
toString. - Приведення рядка до числа: Коли порівнюється рядок з числом, JavaScript намагається перетворити рядок у число. У цьому випадку порожній рядок
""(рядкова форма порожнього масиву) перетворюється на0.
Приклад 1: Перетворення порожнього рядка на число
console.log(Number("")); // 0
Приклад 2: Перетворення масиву в рядок
Коли ви використовуєте об'єкт у контексті, де очікується рядок (наприклад, при конкатенації з рядком), JavaScript віддає перевагу методу toString().
console.log([] + "hello"); // "hello"
У цьому випадку порожній масив [] спочатку перетворюється на порожній рядок "", а потім до цього рядка додається "hello", що дає результат "hello".
Приклад 3: Перетворення масиву на число
Коли об'єкт використовується в порівнянні з числом, JavaScript перетворює об'єкт у примітивне значення.
console.log([1] == 1); // true
У цьому випадку [1] спочатку перетворюється на рядок "1", а потім рядок "1" приводиться до числа 1. Тому вираз 1 == 1 дає результат true.
Ви також можете перевірити перетворення [1]:
console.log(Number([1]) + 1); // 2
Чому це важливо?
Хоча ця поведінка може здатися незначною деталлю, вона ілюструє більшу проблему при використанні оператора == у JavaScript. Приведення типів може призвести до несподіваних результатів, особливо при складних порівняннях.
Наприклад:
console.log(0 == '') // true
console.log(0 == false) // true
console.log([] == false) // true
console.log(null == undefined) // true
Усі ці порівняння можуть здатися дивними на перший погляд, але вони є результатом приведення типів у JavaScript.
Безпечна альтернатива: використовуйте ===
Щоб уникнути непорозумінь і несподіваних помилок, рекомендується завжди використовувати строгий оператор порівняння ===, який не виконує приведення типів.
Таким чином, значення повинні бути одного типу, щоб вважатися рівними.
console.log(0 === []) // false
Великі Роздуми: Ненадійне Порівняння проти Строгого Порівняння
Розуміння різниці між == і === є важливим для написання надійного JavaScript. Ось короткий підсумок:
==(Ненадійне Порівняння): Порівнює значення після виконання приведення типів. Може призвести до несподіваних результатів, якщо ви не обережні.===(Строге Порівняння): Порівнює як значення, так і тип, без будь-якого приведення. Це зазвичай вважається більш безпечним вибором у більшості випадків.
Коли слід використовувати ==?
Є випадки, коли ви можете спеціально використовувати ==, особливо коли потрібно враховувати приведення типів. Наприклад, ви можете захотіти порівняти значення з нечітким типом, як перевірка, чи є введення користувача "істинним" або "хибним".
if (userInput == null) {
// Це зловить як null, так і undefined
}
Але для більшості інших порівнянь краще використовувати оператор ===, щоб уникнути непередбачених помилок.
Висновок
Отже, наступного разу, коли ви заплутаєтесь через порівняння 0 == [], пам'ятайте: це не магія, це просто приведення типів у JavaScript. Розуміння того, як JavaScript обробляє приведення типів, допоможе вам не лише налагоджувати складні порівняння, але й писати більш надійний код. І коли ви сумніваєтесь, завжди використовуйте === для безпечних і більш передбачуваних порівнянь.
Перекладено з: Breaking JavaScript: Why 0 == [] Is Actually True