JavaScript позволяет нам работать с примитивными типами данных – строками, числами и т.д., как будто они являются объектами. У них есть и методы. Мы изучим их позже, а сначала разберём, как это всё работает, потому что, конечно, примитивы – не объекты.
Давайте взглянем на ключевые различия между примитивами и объектами.
Примитив
- Это – значение «примитивного» типа.
- Есть 7 примитивных типов:
string
,number
,boolean
,symbol
,null
,undefined
иbigint
.
Объект
- Может хранить множество значений как свойства.
- Объявляется при помощи фигурных скобок
{}
, например:{name: "Рома", age: 30}
. В JavaScript есть и другие виды объектов: например, функции тоже являются объектами.
Одна из лучших особенностей объектов – это то, что мы можем хранить функцию как одно из свойств объекта.
let roma = {
name: "Рома",
sayHi: function() {
alert("Привет, дружище!");
}
};
roma.sayHi(); // Привет, дружище!
Здесь мы создали объект roma
с методом sayHi
.
Существует множество встроенных объектов. Например, те, которые работают с датами, ошибками, HTML-элементами и т.д. Они имеют различные свойства и методы.
Однако у этих возможностей есть обратная сторона!
Объекты «тяжелее» примитивов. Они нуждаются в дополнительных ресурсах для поддержания внутренней структуры.
Примитив как объект
Вот парадокс, с которым столкнулся создатель JavaScript:
- Есть много всего, что хотелось бы сделать с примитивами, такими как строка или число. Было бы замечательно, если бы мы могли обращаться к ним при помощи методов.
- Примитивы должны быть лёгкими и быстрыми насколько это возможно.
Выбранное решение, хотя выглядит оно немного неуклюже:
- Примитивы остаются примитивами. Одно значение, как и хотелось.
- Язык позволяет осуществлять доступ к методам и свойствам строк, чисел, булевых значений и символов.
- Чтобы это работало, при таком доступе создаётся специальный «объект-обёртка», который предоставляет нужную функциональность, а после удаляется.
Каждый примитив имеет свой собственный «объект-обёртку», которые называются: String
, Number
, Boolean
, Symbol
и BigInt
. Таким образом, они имеют разный набор методов.
К примеру, существует метод str.toUpperCase(), который возвращает строку в верхнем регистре.
Вот, как он работает:
let str = "Привет";
alert( str.toUpperCase() ); // ПРИВЕТ
Очень просто, не правда ли? Вот, что на самом деле происходит в str.toUpperCase()
:
- Строка
str
– примитив. В момент обращения к его свойству, создаётся специальный объект, который знает значение строки и имеет такие полезные методы, какtoUpperCase()
. - Этот метод запускается и возвращает новую строку (показывается в
alert
). - Специальный объект удаляется, оставляя только примитив
str
.
Получается, что примитивы могут предоставлять методы, и в то же время оставаться «лёгкими».
Движок JavaScript сильно оптимизирует этот процесс. Он даже может пропустить создание специального объекта. Однако, он всё же должен придерживаться спецификаций и работать так, как будто он его создаёт.
Число имеет собственный набор методов. Например, toFixed(n) округляет число до n знаков после запятой.
let num = 1.23456;
alert( num.toFixed(2) ); // 1.23
Более подробно с различными свойствами и методами мы познакомимся в главах Числа и Строки.
String/Number/Boolean
предназначены только для внутреннего пользованияНекоторые языки, такие как Java, позволяют явное создание «объектов-обёрток» для примитивов при помощи такого синтаксиса как new Number(1)
или new Boolean(false)
.
В JavaScript, это тоже возможно по историческим причинам, но очень не рекомендуется. В некоторых местах последствия могут быть катастрофическими.
Например:
alert( typeof 0 ); // "число"
alert( typeof new Number(0) ); // "object"!
Объекты в if
всегда дают true
, так что в нижеприведённом примере будет показан alert
:
let zero = new Number(0);
if (zero) {
// zero возвращает "true", так как является объектом
alert( "zero имеет «истинное» значение?!?" );
}
С другой стороны, использование функций String/Number/Boolean
без оператора new
– вполне разумно и полезно. Они превращают значение в соответствующий примитивный тип: в строку, в число, в булевый тип.
К примеру, следующее вполне допустимо:
let num = Number("123"); // превращает строку в число
Особенные примитивы null
и undefined
являются исключениями. У них нет соответствующих «объектов-обёрток», и они не имеют никаких методов. В некотором смысле, они «самые примитивные».
Попытка доступа к свойствам такого значения возвратит ошибку:
alert(null.test); // ошибка
Итого
- Все примитивы, кроме
null
иundefined
, предоставляют множество полезных методов. Мы познакомимся с ними поближе в следующих главах. - Формально эти методы работают с помощью временных объектов, но движки JavaScript внутренне очень хорошо оптимизируют этот процесс, так что их вызов не требует много ресурсов.