Откуда методы у типов number, string и boolean в JS?

Прочитав эту заметку, вы никогда не захотите писать на JavaScript. Но подождите! В работе эти проблемы не всплывают почти никогда. Я специально для вас залезу в этот тёмный подвал JS, чтобы поведать о том, как работает (255).toString(16) и ('me: hello').substr(4) и откуда у примитивных типов number, string и boolean методы?

Элегантный трюк JS

Как мы знаем, эти типы примитивные, то есть их значения — не объекты. Каждому «интересному» примитивному типу соответствует класс: Number, String и Boolean. Методы (toString, toLowerCase, substr) определены у этих типов-обёрток.

И каждый раз когда мы пытаемся получить свойство (или метод) примитивного значения, оно автоматически оборачивается в соответствующий объект, так что ('x').toLowerCase() превращается в (new String('x')).toLowerCase().

Такое оборачивание называется Boxing — положить в коробочку. После выполнения метода объект-обёртка просто выбрасывается.

Объекты типа Number — настоящие объекты, со всеми вытекающими бонусами и проблемами: new Number(3) !== new Number(3), потому что теперь значения сравниваются по ссылке.

Никогда не используйте типы-обёртки с new как конструктор. Скорее всего, вы хотите именно значение примитивного типа: Number('3') === 3.

Попрактикуемся?

На собеседованиях мне несколько раз давали хитрую (но бесполезную) задачку. Что произойдет в результате выполнения этого кода:

const x = 10;
x.hello = 'hello';
console.log(x.hello);

Если вы знаете про Boxing, то всё должно быть понятно — попробуйте! Пишите ответы и вопросы в комментариях!