TLDR: Примусьте себе використовувати потрійні рівні.
Я ненавмисно знайшов цей мем JavaScript на Reddit, і це найкращий із усіх, які я коли-небудь бачив.
Ви можете перевірити точність цього мему, запустивши кожен фрагмент коду в Інструментах розробника. Результат не дивний, але все одно наче розчаровує.
Звичайно, цей маленький експеримент змусив мене задуматися ...
Чому це відбувається?
Маючи досвід, я навчився сприймати гладкі сторони JavaScript, опускаючи його колючі сосни. Тим не менше, подробиці цієї кутової справи мене все ще збентежили.
Це як Кайл Сімпсон каже ...
"Я не думаю, що ніхто ніколи насправді не знає JS, але не зовсім".
Коли ці випадки спливають, найкраще звернутися до джерела - офіційної специфікації ECMAScript, з якої побудований JavaScript.
Маючи специфікацію в руках, давайте глибоко зрозуміємо, що тут відбувається.
Панель 1 - Введення примусу
Якщо ви працюєте 0 == "0"
в консолі розробника, чому вона повертається true
?
0
є числом і "0"
є рядком, вони ніколи не повинні бути однаковими! Більшість мов програмування поважають це. 0 == "0"
в Java, наприклад, повертає це:
error: incomparable types: int and String
Це цілком логічно. Якщо ви хочете порівняти int та String в Java, спочатку потрібно перетворити їх на один і той же тип.
Але це JavaScript, все!
Коли ви порівнюєте два значення за допомогою ==
, одне із значень може зазнати примусу .
Примус - Автоматична зміна значення з одного типу на інший.
Ключовим словом тут є автоматично . Замість того, щоб явно конвертувати ваші типи, JavaScript робить це за вами за кадром.
Це зручно, якщо ви навмисно його використовуєте, але потенційно шкідливо, якщо ви не знаєте про його наслідки.
Ось офіційна специфікація мови ECMAScript щодо цього. Перефразую відповідну частину:
Якщо x - число, а y - рядок, поверніть x == ToNumber (y)
Отже, для нашого випадку 0 == "0"
:
Оскільки 0 - це число, а "0" - це рядок, поверніть 0 == ToNumber ("0")
Наш рядок "0"
був таємно перетворений у 0
, і тепер у нас є збіг!
0 == "0" // true // The second 0 became a number! // so 0 equals 0 is true....
Дивно, правда? Ну звикай, ми навіть не наполовину закінчили.
Панель 2 - Масиви теж примусові
Ця нісенітниця не обмежується примітивами, такими як рядки, числа або логічні значення. Ось наше наступне порівняння:
0 == [] // true // What happened...?
Знову примус! Перефразую відповідну частину специфікації:
Якщо x - рядок або число, а y - об'єкт, поверніть x == ToPrimitive (y)
Тут є три речі:
1. Так, масиви - це об’єкти
Вибачте, що зламав вас.
2. Порожній масив стає порожнім рядком
Знову ж за специфікацією, JS спочатку шукає метод об’єкта, toString
щоб примусити його.
У разі масивів toString
об'єднує всі його елементи і повертає їх у вигляді рядка.
[1, 2, 3].toString() // "1,2,3" ['hello', 'world'].toString() // "hello,world"
Оскільки наш масив порожній, нам нема до чого приєднуватися! Тому ...
[].toString() // ""
Специфікація ToPrimitive
перетворює цей порожній масив на порожній рядок. Посилання тут і тут для вашої зручності (або плутанини).
3. Порожній рядок тоді стає 0
Ви не можете придумати ці речі. Тепер, коли ми примусили масив ""
, ми повернулися до першого алгоритму ...
Якщо x - число, а y - рядок, поверніть x == ToNumber (y)
Отже для 0 == ""
Оскільки 0 - це число, а "" - це рядок, поверніть 0 == ToNumber ("")
ToNumber("")
повертає 0.
Тому 0 == 0
ще раз ...
Панель 3 - Швидкий підсумок
Це правда
0 == "0" // true
Тому що примус перетворює це на 0 == ToNumber("0")
.
Це правда
0 == [] // true
Оскільки примус діє двічі:
ToPrimitive([])
дає порожній рядок- Тоді
ToNumber("")
дає 0.
Тоді скажіть мені ... згідно з наведеними правилами, що це повинно повернути?
"0" == []
Панель 4 - FALSE!
ПОМИЛКОВИЙ! Правильно.
Ця частина має сенс, якщо ви зрозуміли правила.
Ось наше порівняння:
"0" == [] // false
Знову посилання на специфікацію:
Якщо x - рядок або число, а y - об'єкт, поверніть x == ToPrimitive (y)
Це означає...
Оскільки "0" є рядком, а [] - об'єктом, поверніть x == ToPrimitive ([])
ToPrimitive([])
повертає порожній рядок. Зараз порівняння стало
"0" == ""
"0"
і ""
є обома рядками, тому JavaScript не вимагає більше примусу . Ось чому ми отримуємо false
.
Висновок
Використовуйте потрійну рівність і міцно спайте вночі.
0 === "0" // false 0 === [] // false "0" === [] // false
Це повністю уникає примусу, тому, мабуть, це також ефективніше!
Але збільшення продуктивності майже безглуздо. Справжній виграш - це підвищена впевненість у вашому коді, що робить це додаткове натискання клавіш цілком вартим.
Хочете безкоштовно коучинг?
Якщо ви хочете призначити безкоштовний 15-30-хвилинний дзвінок, щоб обговорити питання розвитку Front-End щодо коду, інтерв’ю, кар’єри чи чогось іншого, слідкуйте за мною у Twitter та DM.
Після цього, якщо вам сподобається наша перша зустріч, ми можемо обговорити постійні тренерські стосунки, які допоможуть вам досягти ваших цілей розвитку Front-End!
Дякуємо за читання
Щоб отримати більше подібного вмісту, перегляньте //yazeedb.com!
До наступного разу!