Кратко
Когда объект используется в операции, требующей примитива (obj + 1, obj == 'text'), JavaScript пытается его преобразовать. Порядок: Symbol.toPrimitive(hint) → valueOf() → toString(). hint указывает тип: 'number', 'string' или 'default'.
Подробно
Преобразование вызывается при:\n- obj + number (арифметика)\n- obj + string (конкатенация)\n- obj == primitive (сравнение)\n- Шаблонная строка: \${obj}\n\nАлгоритм ToPrimitive(obj, hint):\n\n1. Если есть Symbol.toPrimitive — вызывается он:\nconst obj = {\n [Symbol.toPrimitive](hint) {\n if (hint === 'number') return 42;\n if (hint === 'string') return 'hello';\n return 'default'; // hint === 'default'\n }\n};\n\n2. Если нет — вызывается valueOf(), потом toString():\nconst obj = {\n valueOf() { return 100; },\n toString() { return 'hello'; }\n};\n\nobj + 1 // 101 (valueOf: 100 + 1)\n\${obj} // 'hello' (toString)\n\nhint:'default' используется для + и ==.\n\nПрактический пример:\nclass Money {\n constructor(amount, currency) {\n this.amount = amount;\n this.currency = currency;\n }\n\n [Symbol.toPrimitive](hint) {\n if (hint === 'number') return this.amount;\n return \${this.amount} \${this.currency};\n }\n}\n\nconst price = new Money(100, 'USD');\nconsole.log(price + 50); // 150\nconsole.log(\${price}); // '100 USD'\nconsole.log(price == 100); // true
Ментальная модель
ToPrimitive — как переводчик. Когда JavaScript встречает объект там, где нужен примитив (число, строка), он спрашивает: «Можешь дать мне число? Нет? А строку? Нет? Тогда попробую valueOf, потом toString.» Symbol.toPrimitive — личный переводчик объекта.
Примеры
**Самый простой:**
const obj = {
valueOf() { return 10; }
};
console.log(obj + 5); // 15 (valueOf)
console.log(`${obj}`); // '[object Object]' (toString)
console.log(obj == 10); // truevalueOf вызывается при арифметике, toString — при шаблонных строках.
**Простой:**
const obj = {
[Symbol.toPrimitive](hint) {
console.log('hint:', hint);
if (hint === 'number') return 42;
if (hint === 'string') return 'hello';
return 'default';
}
};
console.log(obj + 1); // hint: default, 43
console.log(`${obj}`); // hint: string, 'hello'
console.log(obj * 2); // hint: number, 84Symbol.toPrimitive получает hint в зависимости от контекста.
**Реальный пример:**
class Temperature {
constructor(celsius) {
this.celsius = celsius;
}
[Symbol.toPrimitive](hint) {
if (hint === 'number') return this.celsius;
if (hint === 'string') return `${this.celsius}°C`;
return this.celsius;
}
}
const temp = new Temperature(23);
console.log(temp + 7); // 30 (number)
console.log(`${temp}`); // '23°C' (string)
console.log(temp > 20); // true (number)Реальный пример: класс Temperature с преобразованием.
Частые ошибки
**Неправильно:** Думать, что + всегда вызывает valueOf
**Почему:** Если один из операндов — строка, + конкатенирует и вызывает toString.
**Правильно:** obj + '' → toString. obj + 1 → valueOf (если hint='default').
**Неправильно:** Забывать, что == вызывает ToPrimitive
**Почему:** obj == 10 вызывает преобразование объекта.
**Правильно:** Используйте ===, если не хотите преобразований.
Важно запомнить
- Symbol.toPrimitive — приоритет над valueOf/toString
- hint: 'number', 'string', 'default'
- valueOf — для чисел, toString — для строк
- + и == используют hint 'default'
- Шаблонные строки используют hint 'string'
Связь
Назад: Вы знаете типы (J3) и операторы (J4). Этот урок объясняет, что происходит, когда объекты взаимодействуют с примитивами.
Вперёд: Следующий урок (JV4) — Symbol — примитивный тип для уникальных идентификаторов.