Vue Front-end Инженер

Vue Front-end Инженер

Роадмап навыков для прокачки

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

Язык JavaScript (ES5)ОбщееОсновное

Основная идея

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

Ключевые аспекты

  • Строгое сравнение (===) — сравнивает и значение, и тип данных
  • Нестрогое сравнение (==) — сначала приводит типы, потом сравнивает значения
  • Type coercion — автоматическое преобразование типов при нестрогом сравнении
  • null и undefined — равны только друг другу при ==, но не при ===

Плюсы строгого сравнения

  • Предсказуемое поведение без неожиданных преобразований
  • Легче отлаживать и понимать код
  • Избегает скрытых багов от автоматического приведения типов

Минусы нестрогого сравнения

  • Сложные правила приведения типов
  • Неочевидные результаты сравнения
  • Потенциальный источник багов

Частые ошибки на собеседованиях

  • Не знают, что 0 == "" возвращает true
  • Путают поведение null == undefined (true) и null === undefined (false)
  • Забывают, что NaN не равен ничему, включая самого себя
  • Не понимают порядок приведения типов при нестрогом сравнении

Введение и проблематика

В JavaScript существуют два оператора сравнения: строгое (===, !==) и нестрогое (==, !=). Понимание разницы между ними критически важно для написания надёжного кода и успешного прохождения собеседований.

Строгое сравнение также называют "сравнением без приведения типов" (strict equality), а нестрогое — "абстрактным сравнением" (abstract equality).

Почему это важно?

Нестрогое сравнение может приводить к неожиданным результатам из-за автоматического приведения типов (type coercion). Это частая причина багов в JavaScript-приложениях.


Базовая теория

Строгое сравнение (===)

Оператор строгого сравнения возвращает true только если оба операнда имеют одинаковый тип И одинаковое значение.

Code Example 1: Что вернёт каждое сравнение и почему?

js
// Строгое сравнение — типы должны совпадать
5 === 5        // true (число === число)
5 === "5"      // false (число !== строка)
true === 1     // false (boolean !== число)
null === null  // true

Нестрогое сравнение (==)

Оператор нестрогого сравнения сначала приводит операнды к одному типу, а затем сравнивает значения.

Code Example 2: Что вернёт каждое сравнение? Какой тип приводится?

js
// Нестрогое сравнение — происходит приведение типов
5 == "5"       // true ("5" приводится к числу 5)
true == 1      // true (true приводится к 1)
false == 0     // true (false приводится к 0)
null == undefined // true (специальное правило)

Правила приведения типов

Алгоритм нестрогого сравнения

flowchart TD A[x == y] --> B{Типы одинаковые?} B -->|Да| C[Сравнить значения] B -->|Нет| D{null или undefined?} D -->|Да| E[null == undefined true] D -->|Нет| F{Число и строка?} F -->|Да| G[Строку в число] F -->|Нет| H{Boolean?} H -->|Да| I[Boolean в число] H -->|Нет| J{Объект и примитив?} J -->|Да| K[Объект valueOf/toString]

Таблица приведения типов

ВыражениеРезультатОбъяснение
"5" == 5trueСтрока "5" → число 5
true == 1trueBoolean true → число 1
false == 0trueBoolean false → число 0
"" == 0trueПустая строка → число 0
" " == 0trueСтрока с пробелом → 0
null == undefinedtrueСпециальное правило
[] == falsetrue[] → "" → 0, false → 0
[] == ""true[] → ""

Практические примеры

Сравнение разных типов

Code Example 3: Какие результаты вернёт нестрогое сравнение? Какие из них неожиданные?

js
// Нестрогое сравнение — неожиданные результаты
console.log(0 == "");        // true
console.log(0 == "0");       // true
console.log("" == "0");      // false (!)
 
console.log(false == "0");   // true
console.log(false == "");    // true
console.log(false == []);    // true
 
console.log(null == undefined); // true
console.log(null == 0);         // false (!)

Проверка на null и undefined

Code Example 4: Что вернёт processValue() для каждого аргумента? Почему используется == вместо ===?

js
// Нестрогое сравнение удобно для проверки null/undefined
function processValue(value) {
  // Проверяет и null, и undefined одновременно
  if (value == null) {
    return 'Значение отсутствует';
  }
  return value;
}
 
processValue(null);      // 'Значение отсутствует'
processValue(undefined); // 'Значение отсутствует'
processValue(0);         // 0
processValue("");        // ""
⚠️

Это единственный случай, когда нестрогое сравнение может быть оправдано — для одновременной проверки null и undefined.


Пограничные кейсы

NaN — особый случай

Code Example 5: Почему NaN === NaN возвращает false? Как правильно проверить NaN?

js
// NaN не равен ничему, даже самому себе
NaN == NaN   // false
NaN === NaN  // false
 
// Для проверки NaN используйте:
Number.isNaN(NaN)     // true
Object.is(NaN, NaN)   // true
🚫

Никогда не сравнивайте с NaN через == или ===. Используйте Number.isNaN().

Объекты сравниваются по ссылке

Code Example 6: Почему obj1 === obj2 возвращает false? Когда объекты равны?

js
const obj1 = { a: 1 };
const obj2 = { a: 1 };
const obj3 = obj1;
 
obj1 == obj2   // false (разные ссылки)
obj1 === obj2  // false (разные ссылки)
obj1 === obj3  // true (одна ссылка)
 
// То же для массивов
[] == []   // false
[] === []  // false

Странные, но валидные случаи

js
// Эти результаты нужно просто запомнить
[] == ![]     // true (!)
// ![] → false → 0
// [] → "" → 0
// 0 == 0 → true
 
"true" == true   // false
// true → 1
// "true" → NaN
// 1 == NaN → false

Плюсы и минусы

Аспект=== (строгое)== (нестрогое)
ПредсказуемостьВысокаяНизкая
Читаемость кодаПонятноЗапутанно
ПроизводительностьЧуть быстрееЧуть медленнее
БезопасностьБезопаснееПотенциальные баги
Проверка null/undefinedНужно два условияОдно условие

Рекомендации

Лучшая практика: Всегда используйте строгое сравнение (===), кроме случаев осознанной проверки value == null.

js
// Рекомендуется
if (value === null || value === undefined) { }
// или
if (value == null) { } // только для null/undefined
 
// Не рекомендуется
if (value == false) { }  // Плохо: может пропустить 0, ""
if (value == 0) { }      // Плохо: может пропустить "", false

Вопросы интервьюера

Q: В чём разница между == и ===?

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

Q: Что вернёт null == undefined?

true. Это специальное правило в спецификации — они равны друг другу при нестрогом сравнении.

Q: Почему [] == false возвращает true?

Массив приводится к строке "", строка к числу 0. Boolean false приводится к 0. Итого: 0 == 0 → true.

Q: Как проверить, является ли значение NaN?

Использовать Number.isNaN(value) или Object.is(value, NaN). Сравнение value === NaN всегда вернёт false.

Q: Когда оправдано использование ==?

Только для проверки value == null, что покрывает и null, и undefined одновременно.


Источники

Code Example 1: Strict comparison (===)

❓ Что вернёт каждое сравнение и почему?

js
5 === 5
5 === "5"
true === 1
null === null

Code Example 2: Non-strict comparison (==)

❓ Что вернёт каждое сравнение? Какой тип приводится?

js
5 == "5"
true == 1
false == 0
null == undefined

Code Example 3: Comparison table

❓ Какие результаты вернёт нестрогое сравнение? Какие из них неожиданные?

Нестрогое сравнение ==:

js
console.log(0 == "");
console.log(0 == "0");
console.log("" == "0");
 
console.log(false == "0");
console.log(false == "");
console.log(false == []);
 
console.log(null == undefined);
console.log(null == 0);

Строгое сравнение ===:

js
console.log(0 === "");
console.log(0 === "0");
console.log("" === "0");
 
console.log(false === "0");
console.log(false === "");
console.log(false === []);
 
console.log(null === undefined);
console.log(null === 0);

Code Example 4: Checking null/undefined

❓ Что вернёт processValue() для каждого аргумента? Почему используется == вместо ===?

js
function processValue(value) {
  if (value == null) {
    return 'Значение отсутствует';
  }
  return value;
}
 
processValue(null);
processValue(undefined);
processValue(0);
processValue("");

Code Example 5: NaN comparison

❓ Почему NaN === NaN возвращает false? Как правильно проверить NaN?

js
NaN == NaN
NaN === NaN
 
Number.isNaN(NaN)
Object.is(NaN, NaN)

Code Example 6: Objects comparison by reference

❓ Почему obj1 === obj2 возвращает false? Когда объекты равны?

js
const obj1 = { a: 1 };
const obj2 = { a: 1 };
const obj3 = obj1;
 
obj1 == obj2
obj1 === obj2
obj1 === obj3
 
[] == []
[] === []