DevSurge 💦

Операторы равенства и строгого равенства

Cover Image for Операторы равенства и строгого равенства
Mark Nelyubin
Mark Nelyubin

При написании программного обеспечения более простое решение почти всегда является лучшим. Если для того, чтобы воспользоваться какой-то функцией, мне сначала нужно запомнить список правил, я стараюсь избегать этого. Не потому, что эта функция не может быть ценной, а потому, что я не доверяю себе в запоминании всех нюансов правил.

Вот почему я всегда использую оператор строгого равенства (===) вместо оператора равенства (==). Оба оператора решают похожие задачи, но стандартные настройки строгого равенства намного удобнее для меня в качестве пользователя.

Оператор строгого равенства (тройное равенство)

При использовании тройного равенства === необходимо помнить два правила - строгое равенство (для сравнения примитивных значений) и ссылочное равенство (для сравнения ссылочных значений).

Строгое равенство

Строгое равенство проверяет, что тип (число, строка, булево и т.д.) и значение одинаковы:

  • Если и значение, и тип одинаковы, получим true.
  • Если тип одинаков, но значение разное, получим false.
  • Если значение одинаково, но тип разный, получим false.
5 === 5 // true. Одинаковый тип и значение
5 === 4 // false. Тип одинаковый, значения разные
5 === "5" // false. Значение одинаковое, тип разный. 

true === true // true. Одинаковый тип и значение
true === false // false. Тип одинаковый, значения разные
true === 'true' // false. Значение одинаковое, тип разный. 

Кажется достаточно простым. Но есть нюанс. Это правило нарушается, когда мы начинаем сравнивать объекты (ссылочные типы), а не примитивы.

Ссылочное равенство

Как мы видели в предыдущем примере, примитивы сравниваются по значению. При использовании тройного равенства для сравнения объектов будут сравниваться ссылки (участки в памяти).

{} === {} // false. Одинаковый тип, одинаковое значение, разная ссылка на участок в памяти. ❌
[] === [] // false. Одинаковый тип, одинаковое значение, разная ссылка на участок в памяти. ❌
{ name: 'Meg' } === { name: 'Meg' } // false. Одинаковый тип, одинаковое значение, разная ссылка на участок в памяти. ❌

Каждый из приведенных примеров имеет один и тот же тип, и как будто одинаковое значение. Но, у объектов используется ссылочное значение — JavaScript сравнивает ссылки на участки в памяти, а не фактическое значение. В каждом из примеров эти ссылки и местоположение в памяти различны, поэтому всегда получаем false.

Рассмотрим пример. Присвоим двум переменным одну и ту же ссылку в памяти, а затем применим к ним оператор тождества.

const user = { name: "Mark" };
const person = user;
console.log(user === person); // true

person.name = "Вася Пупкин";
console.log(user === person); // true
console.log(user.name); // "Вася Пупкин"

И person, и user ссылаются на одно и то же место в памяти, поэтому получаем true.

Если вы знаете про равенство ссылочных типов, то в с оператором тождества (===) все работает так, как вы ожидаете. Вот таблица равенства, чтобы доказать это:

Article Image

Оператор равенства (двойное равенство)

Оператор равенства (==) же ведет себя не так, как вы ожидаете (только если вы не знакомы с ним очень хорошо).

"1" == 1 // true
null == undefined // true
0 == '' // true
'0' == false // true
[1] == true // true 

Что здесь происходит? Обратите внимание — каждое сравнение выполняется между разными типами. В случае строгого равенства (===), все они вернут false, так как все они относятся к разным типам. С оператором равенства (==) все не так просто. Вместо того, чтобы возвращать false при несовпадении типов, он пытается преобразовать их в один тип.

Почему "1" == 1 возвращает true? JavaScript видит оператор равенства, видит разные типы, преобразует строку "1" в число 1, чтобы сравнить. Получается 1 == 1, что является истиной.

Именно этап приведения типов делает оператор равенства (==) таким непредсказуемым. В качестве доказательства приведу ту же таблицу, только теперь для обычного равенства (==):

Article Image

Если вы, как и другие разработчики вашей команды, в совершенстве знаете все правила принудительного согласования типов JavaScript, можете смело использовать оператор равенства (==). Если вы похожи на меня и предпочитаете использовать инструмент, который работает так, как вы ожидаете, придерживайтесь оператора тождества (===).


Другие материалы

Cover Image for TypeScript Utility Types — вспомогательные типы и области их применения

TypeScript Utility Types — вспомогательные типы и области их применения

что такое Utility Types в TypeScript, расскажу про основные вспомогательные типы, и покажу, как применять их на реальных проектах.

Mark Nelyubin
Mark Nelyubin
Cover Image for Принципы SOLID с примерами на JS и Vue

Принципы SOLID с примерами на JS и Vue

Расскажу про принципы SOLID с актуальными примерами на JavaScript, Vue, React.

Mark Nelyubin
Mark Nelyubin