Найкращий мем JavaScript, який я коли-небудь бачив, детально пояснений

TLDR: Примусьте себе використовувати потрійні рівні.

Я ненавмисно знайшов цей мем JavaScript на Reddit, і це найкращий із усіх, які я коли-небудь бачив.

best-js-meme-to-date-2

Ви можете перевірити точність цього мему, запустивши кожен фрагмент коду в Інструментах розробника. Результат не дивний, але все одно наче розчаровує.

Звичайно, цей маленький експеримент змусив мене задуматися ...

Чому це відбувається?

чому-це-трапляється

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

Це як Кайл Сімпсон каже ...

"Я не думаю, що ніхто ніколи насправді не знає JS, але не зовсім".

Коли ці випадки спливають, найкраще звернутися до джерела - офіційної специфікації ECMAScript, з якої побудований JavaScript.

Маючи специфікацію в руках, давайте глибоко зрозуміємо, що тут відбувається.

Панель 1 - Введення примусу

панель-1-1

Якщо ви працюєте 0 == "0"в консолі розробника, чому вона повертається true?

0є числом і "0"є рядком, вони ніколи не повинні бути однаковими! Більшість мов програмування поважають це. 0 == "0"в Java, наприклад, повертає це:

error: incomparable types: int and String 

Це цілком логічно. Якщо ви хочете порівняти int та String в Java, спочатку потрібно перетворити їх на один і той же тип.

Але це JavaScript, все!

this-is-javascript

Коли ви порівнюєте два значення за допомогою ==, одне із значень може зазнати примусу .

Примус - Автоматична зміна значення з одного типу на інший.

Ключовим словом тут є автоматично . Замість того, щоб явно конвертувати ваші типи, 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 - Масиви теж примусові

панель-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() // "" 

empty-array-coerces-to-empty-string-1

Специфікація ToPrimitiveперетворює цей порожній масив на порожній рядок. Посилання тут і тут для вашої зручності (або плутанини).

3. Порожній рядок тоді стає 0

empty-strings-become-0

Ви не можете придумати ці речі. Тепер, коли ми примусили масив "", ми повернулися до першого алгоритму ...

Якщо x - число, а y - рядок, поверніть x == ToNumber (y)

Отже для 0 == ""

Оскільки 0 - це число, а "" - це рядок, поверніть 0 == ToNumber ("")

ToNumber("") повертає 0.

Тому 0 == 0ще раз ...

примус-щоразу-2

Панель 3 - Швидкий підсумок

панель-3-1

Це правда

0 == "0" // true 

Тому що примус перетворює це на 0 == ToNumber("0").

Це правда

0 == [] // true 

Оскільки примус діє двічі:

  1. ToPrimitive([]) дає порожній рядок
  2. Тоді ToNumber("")дає 0.

Тоді скажіть мені ... згідно з наведеними правилами, що це повинно повернути?

"0" == [] 

Панель 4 - FALSE!

панель-4-1

ПОМИЛКОВИЙ! Правильно.

Ця частина має сенс, якщо ви зрозуміли правила.

Ось наше порівняння:

"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!

До наступного разу!