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

Почему у примитивов есть методы?

1.8 Middle🔥 181 комментариев
#JavaScript Core

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

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

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

Почему у примитивов в JavaScript есть методы

Это один из самых интересных вопросов о том, как работает JavaScript. На первый взгляд кажется странным, что примитивные типы (строки, числа) могут иметь методы, ведь они не объекты. Ответ лежит в механизме автоматического упаковывания (autoboxing) и объектных обёрток (wrapper objects).

1. Примитивы в JavaScript

В JavaScript есть 7 примитивных типов:

// Примитивы (не объекты)
const str = 'hello';        // string
const num = 42;             // number
const bool = true;          // boolean
const sym = Symbol('id');   // symbol
const big = 100n;           // bigint
const nul = null;           // null
const undef = undefined;    // undefined

// Проверить тип
console.log(typeof str);    // 'string'
console.log(typeof num);    // 'number'

2. Но примитивы имеют методы

const str = 'hello';

// У строки есть методы, хотя это примитив!
const upper = str.toUpperCase();
console.log(upper); // 'HELLO'

const num = 42;
const numStr = num.toString();
console.log(numStr); // '42'

const hasH = str.includes('h');
console.log(hasH); // true

Как это возможно? Благодаря объектным обёрткам (wrapper objects).

3. Объектные обёртки (Wrapper Objects)

Для каждого примитива существует встроенная объектная обёртка:

// Примитив
const strPrimitive = 'hello';

// Объектная обёртка
const strObject = new String('hello');

// Это разные вещи
console.log(typeof strPrimitive);  // 'string'
console.log(typeof strObject);     // 'object'

// Но они одинаковые по значению
console.log(strPrimitive == strObject);   // true (слабое сравнение)
console.log(strPrimitive === strObject);  // false (строгое сравнение)

Обёртки для других примитивов:

// Числа
const numPrimitive = 42;
const numObject = new Number(42);

// Логические значения
const boolPrimitive = true;
const boolObject = new Boolean(true);

// Символы (особая обёртка)
const symPrimitive = Symbol('id');
const symObject = Object(symPrimitive);

4. Автоматическое упаковывание (Autoboxing)

Когда ты обращаешься к методу или свойству примитива, JavaScript автоматически преобразует примитив в объект, вызывает метод, а затем выбрасывает объект:

const str = 'hello';
const upper = str.toUpperCase();

// Что происходит под капотом:
// 1. Создаётся временный объект String
const tempObject = new String('hello');
// 2. Вызывается метод на этом объекте
const result = tempObject.toUpperCase();
// 3. Возвращается результат
// 4. Временный объект выбрасывается

console.log(upper); // 'HELLO'

Визуализация процесса:

const num = 42;
console.log(num.toString());  // Внутри происходит:
                               // new Number(42).toString()
                               // -> '42'
                               // Объект Number удаляется

const str = 'abc';
console.log(str[0]);          // Внутри:
                               // new String('abc')[0]
                               // -> 'a'
                               // Объект String удаляется

5. Методы строк (примеры)

const str = 'JavaScript';

// Все эти методы работают благодаря autoboxing
console.log(str.length);           // 10
console.log(str.toUpperCase());    // 'JAVASCRIPT'
console.log(str.toLowerCase());    // 'javascript'
console.log(str.charAt(0));        // 'J'
console.log(str.charCodeAt(0));    // 74
console.log(str.indexOf('Script')); // 4
console.log(str.slice(0, 4));      // 'Java'
console.log(str.includes('Java')); // true
console.log(str.split(''));        // ['J','a','v','a',...]

6. Методы чисел (примеры)

const num = 123.456;

// Все методы вызывают autoboxing
console.log(num.toString());       // '123.456'
console.log(num.toFixed(2));       // '123.46'
console.log(num.toExponential()); // '1.23456e+2'
console.log(num.toPrecision(5));   // '123.46'

7. Методы boolean (примеры)

const bool = true;

// Методы boolean
console.log(bool.toString());      // 'true'
console.log(bool.valueOf());       // true

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

Удобство

// Без autoboxing пришлось бы писать так:
const str = String.prototype.toUpperCase.call('hello');

// С autoboxing просто:
const str = 'hello'.toUpperCase();

Единственное API

// Строка и объект String имеют одинаковые методы
const primitive = 'hello';
const object = new String('hello');

console.log(primitive.charAt(0));   // 'h'
console.log(object.charAt(0));      // 'h'

// Программист не должен беспокоиться о разнице

9. Отличие от добавления свойств

const str = 'hello';

// Попытка добавить свойство к примитиву
str.myProperty = 'test';

// Это НЕ работает (или работает, но свойство теряется)
console.log(str.myProperty);  // undefined

// Почему? Потому что:
// 1. Создаётся временный объект new String('hello')
// 2. На него добавляется свойство myProperty
// 3. Объект выбрасывается
// 4. При чтении снова создаётся новый объект без свойства

// А методы существуют потому что они уже определены в String.prototype

10. Prototype chain для примитивов

const str = 'hello';

// Цепочка прототипов для строки:
// 'hello' (примитив)
//   -> String.prototype (методы: toUpperCase, charAt, и т.д.)
//     -> Object.prototype (методы: toString, valueOf и т.д.)
//       -> null

console.log('toUpperCase' in str);  // true
console.log('toString' in str);     // true

// Проверить, есть ли метод в цепочке
console.log(String.prototype.toUpperCase);  // [Function: toUpperCase]

11. null и undefined - исключения

const nul = null;
const undef = undefined;

// У null и undefined нет методов!
nul.toString();      // TypeError: Cannot read property 'toString' of null
undef.toString();    // TypeError: Cannot read property 'toString' of undefined

// Потому что для них нет объектных обёрток
// Но у них есть специальные методы в глобальном Object

// Если нужно преобразовать null/undefined:
console.log(String(null));     // 'null'
console.log(String(undefined)); // 'undefined'

12. Практический пример: цепочка методов

const sentence = 'hello world';

// Благодаря autoboxing можно писать цепочку методов
const result = sentence
  .split(' ')                      // Массив
  .map(word => word.toUpperCase()) // ['HELLO', 'WORLD']
  .join('-');                      // 'HELLO-WORLD'

console.log(result); // 'HELLO-WORLD'

// Каждый метод работает благодаря autoboxing:
// sentence.split() -> new String(sentence).split()
// word.toUpperCase() -> new String(word).toUpperCase()

13. Производительность

// Autoboxing работает быстро благодаря оптимизациям движков
const str = 'test';

// Это почти не имеет оверхеда
for (let i = 0; i < 1000000; i++) {
  str.toUpperCase();
}

// Движок оптимизирует это и не создаёт объект каждый раз

14. Когда нужны объектные обёртки явно

// Обычно НЕ нужно явно создавать обёртки
const numPrimitive = 42;
const numObject = new Number(42);

// Объекты работают медленнее
// И сравнения ведут себя странно
console.log(numObject == 42);      // true
console.log(numObject === 42);     // false (разные типы)

// Используй примитивы
const num = 42; // Хорошо
const num2 = new Number(42); // Плохо (редко нужно)

15. Что запомнить

Ключевые концепции

  • Примитивы не объекты, но выглядят как объекты
  • Autoboxing - механизм, который оборачивает примитив в объект при вызове метода
  • String.prototype, Number.prototype и т.д. содержат методы
  • Wrapper objects создаются временно и затем выбрасываются
  • null и undefined не имеют объектных обёрток

Практическое применение

// Работает благодаря autoboxing
const str = 'hello';
str.toUpperCase();      // Ok
str.charAt(0);          // Ok
str.length;             // Ok - это свойство

// Не работает (примитив не может иметь свои свойства)
str.custom = 'value';
console.log(str.custom); // undefined

Этот механизм делает JavaScript более удобным языком, скрывая сложность под капотом и позволяя программистам работать с примитивами как с объектами, когда это нужно.

Почему у примитивов есть методы? | PrepBro