← Назад к вопросам

Как проводить сравнение между типами данных?

2.0 Middle🔥 161 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как проводить сравнение между типами данных?

Сравнение в JavaScript - один из самых коварных аспектов языка. Есть два оператора сравнения: == (с type coercion) и === (без coercion). Опытные разработчики всегда используют === по умолчанию.

== vs ===

// == (loose equality) - с приведением типов
0 == false;        // true (тип coercion!)
0 == "";           // true
0 == "0";          // true
"" == false;       // true
null == undefined;  // true

// === (strict equality) - без приведения типов
0 === false;        // false
0 === "";           // false
0 === "0";          // false
"" === false;       // false
null === undefined; // false

Правило железное: ВСЕГДА используйте ===. Оператор == непредсказуем и источник ошибок.

Проблемы с ==

// Интуитивно неправильно
const user = { name: "John" };
if (user == true) {  // true!
  // Выполнится, потому что объект truthy
}

// Парадоксально
const arr = [];
arr == false;     // true
arr == "";        // true
arr == 0;         // true

// Совсем странно
NaN == NaN;       // false
undefined == null; // true (но === false)

Этот список показывает - == не предсказуем. Используйте ===.

Правильное сравнение примитивов

// Числа
const a = 10;
const b = 10;
const c = "10";

a === b;       // true
a === c;       // false - правильно!

// Строки
const str1 = "hello";
const str2 = "hello";
const str3 = new String("hello");

str1 === str2; // true
str1 === str3; // false - разные объекты!
str1 == str3;  // true - нежелательно

// Boolean
const isValid = true;
if (isValid === true) { /* best practice */ }
if (isValid) { /* ok */ }
if (isValid == true) { /* плохо */ }

// null и undefined
const value = null;
value === null;      // true - правильно
value === undefined; // false - правильно
value == null;       // true - нежелательно

Сравнение объектов и массивов

Основное правило: сравниваются ссылки, не содержимое:

// Объекты
const user1 = { id: 1, name: "John" };
const user2 = { id: 1, name: "John" };
const user3 = user1;

user1 === user2; // false - разные объекты
user1 === user3; // true - одна ссылка

// Массивы
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
const arr3 = arr1;

arr1 === arr2; // false - разные массивы
arr1 === arr3; // true - одна ссылка

Для сравнения содержимого нужна помощь:

// Глубокое сравнение объектов
function deepEqual(obj1: any, obj2: any): boolean {
  // Базовая реализация
  if (obj1 === obj2) return true;
  if (obj1 == null || obj2 == null) return false;
  if (typeof obj1 !== "object" || typeof obj2 !== "object") return false;

  const keys1 = Object.keys(obj1);
  const keys2 = Object.keys(obj2);

  if (keys1.length !== keys2.length) return false;

  for (const key of keys1) {
    if (!keys2.includes(key)) return false;
    if (!deepEqual(obj1[key], obj2[key])) return false;
  }

  return true;
}

const user1 = { id: 1, name: "John" };
const user2 = { id: 1, name: "John" };

deepEqual(user1, user2); // true

Сравнение в React

// Проблема - новый объект каждый раз
function MyComponent() {
  const user = { id: 1, name: "John" }; // новый объект на каждый рендер

  useEffect(() => {
    console.log("User changed"); // печатает каждый раз!
  }, [user]); // user !== user на каждом рендере

  return <div>{user.name}</div>;
}

// Решение 1: move outside
const DEFAULT_USER = { id: 1, name: "John" };

function MyComponent() {
  useEffect(() => {
    console.log("User changed"); // печатает один раз
  }, [DEFAULT_USER]);

  return <div>{DEFAULT_USER.name}</div>;
}

// Решение 2: useMemo
function MyComponent() {
  const user = useMemo(() => ({ id: 1, name: "John" }), []);

  useEffect(() => {
    console.log("User changed"); // печатает один раз
  }, [user]);

  return <div>{user.name}</div>;
}

Сравнение специальных значений

// NaN - единственное значение которое не равно себе!
NaN === NaN;  // false
NaN == NaN;   // false

// Правильная проверка
Number.isNaN(NaN);     // true
Object.is(NaN, NaN);   // true

// -0 и +0
-0 === 0;     // true
Object.is(-0, 0); // false (учитывает знак)

// Infinity
Infinity === Infinity; // true
1/0 === Infinity;      // true

Object.is - правильное сравнение

// Object.is исправляет недостатки === для NaN и -0
Object.is(NaN, NaN);     // true
Object.is(0, -0);        // false
Object.is(5, 5);         // true
Object.is(5, "5");       // false

// Практическое использование
const values = [1, 2, NaN, 3];
const hasNaN = values.some(v => Object.is(v, NaN)); // true

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

// Юникод - опасно
const str1 = "e\u0301"; // é (e + острый accent отдельно)
const str2 = "\u00e9"; // é (готовый символ)

str1 === str2; // false - хотя выглядят одинаково!

// Правильное сравнение строк
str1.localeCompare(str2) === 0; // true - сравнивает нормализованно

// Нормализация
const normalized1 = str1.normalize();
const normalized2 = str2.normalize();
normalized1 === normalized2; // true

Сравнение дат

const date1 = new Date("2024-01-01");
const date2 = new Date("2024-01-01");
const date3 = date1;

date1 === date2; // false - разные объекты
date1 === date3; // true

// Правильно - сравниваем time
date1.getTime() === date2.getTime(); // true

// Или используем valueOf
date1.valueOf() === date2.valueOf(); // true

Чеклист правильного сравнения

// 1. ВСЕГДА === по умолчанию
const age = 25;
if (age === 25) { /* good */ }

// 2. Для объектов - сравниваем содержимое
const user1 = { id: 1 };
const user2 = { id: 1 };
if (user1.id === user2.id) { /* good */ }

// 3. Для массивов - сравниваем элементы
const arr1 = [1, 2];
const arr2 = [1, 2];
if (arr1.length === arr2.length && arr1[0] === arr2[0]) { /* good */ }

// 4. Для NaN - используйте Number.isNaN
if (Number.isNaN(value)) { /* good */ }

// 5. Для дат - сравниваем time
if (date1.getTime() === date2.getTime()) { /* good */ }

// 6. Для строк с разными кодировками - normalize
if (str1.normalize() === str2.normalize()) { /* good */ }

Почему === безопаснее

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

Как проводить сравнение между типами данных? | PrepBro