← Назад к вопросам
Как проводить сравнение между типами данных?
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 */ }
Почему === безопаснее
Оператор === предсказуем и явен. Он не скрывает неожиданного поведения. Любой разработчик сразу поймет что вы сравниваете типы. Используйте === и ваш код будет надежнее и понятнее.