Методы – это свойства объектов, в которые записаны функции. Если это так, тогда почему работает такой код:
'hexlet'.toUpperCase(); // "HEXLET"
Из этого кода можно сделать ошибочный вывод что строка это тоже объект, но это не так. В JavaScript строки, логические значения, null и числа реализованы как примитивные значения, у них нет методов. С другой стороны, для каждого такого типа существует собственный конструктор, "упаковывающий" примитивный тип в объект:
typeof 'hexlet'; // "string"
const name = new String('hexlet');
typeof name; // "object"
console.log(name); // "hexlet"
JavaScript автоматически упаковывает примитивные типы в соответствующие объекты, когда встречает вызовы методов на них (и затем автоматически распаковывает). То есть в действительности, все методы которые мы вызываем на строках, хранятся в прототипе конструктора String
. То же самое касается и всех остальных типов:
// Ручная упаковка примитивных значений
const number = new Number(1);
number.toString(); // "1"
const bool = new Boolean(true);
bool.toString(); // "true"
// Автоматическая упаковка
const one = 1;
// Во время вызова происходит упаковка
one.toString(); // "1"
// Обратите внимание что, такой код завершится с ошибкой:
// 1.toString();
// js ожидает, что после точки будет продолжение числа
// А вот так заработает (1).toString();
const yes = true;
// Во время вызова происходит упаковка
yes.toString(); // "true"
Интересно то, как происходит распаковка. Для этого JavaScript автоматически вызывает метод valueOf()
у объекта:
const number = new Number(100);
// Его можно вызвать самостоятельно
number.valueOf(); // 100
// А еще он вызывается в результате разных операций над объектом
const newName = `${number} is a big number`; // "100 is a big number!"
В отличие от упаковки, распаковка выполняется абсолютно для всех объектов. Это позволяет определять valueOf()
самостоятельно:
const words = ['Hello'];
const helloBuilder = (string) => words.push(string);
const build = () => words.join(' ');
helloBuilder.valueOf = () => build();
helloBuilder('from');
helloBuilder('valueOf');
console.log(helloBuilder == 'Hello from valueOf'); // true
Подобным пользуются разные библиотеки, например moment.js для конвертации даты (как объекта) в значение (timestamp):
const date = moment(); // возвращает объект описывающий текущую дату
// с этой датой можно делать всякое
date.startOf('day').fromNow(); // "a day ago"
// Хитрость в том, что оператор `+` приводит к распаковке
// valueOf возвращает текущий timestamp
+date; // 1578624487377
Хотя это работает, такой подход не приветствуется многими разработчиками. Это больше похоже на хак, чем на хороший код.
Вам ответят команда поддержки Хекслета или другие студенты.
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно
Наши выпускники работают в компаниях:
С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.
Зарегистрируйтесь или войдите в свой аккаунт