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