JS Advanced

Преобразование объекта в примитив

Понять, как объекты преобразуются в примитивы через Symbol.toPrimitive, valueOf и toString при операциях +, == и шаблонных строках.

Продвинутый (Advanced)

Кратко

Когда объект используется в операции, требующей примитива (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 — личный переводчик объекта.


Примеры

**Самый простой:**

javascript
const obj = {
  valueOf() { return 10; }
};

console.log(obj + 5);   // 15 (valueOf)
console.log(`${obj}`);  // '[object Object]' (toString)
console.log(obj == 10); // true

valueOf вызывается при арифметике, toString — при шаблонных строках.

**Простой:**

javascript
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, 84

Symbol.toPrimitive получает hint в зависимости от контекста.

**Реальный пример:**

javascript
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 — примитивный тип для уникальных идентификаторов.

Материалы курса JS Advanced — PROlab Academy.