Типы данных JavaScript

JavaScript использует динамическую типизацию переменных (т.е. он является слабо типизированным или динамическим языком), что позволяет:

  1. не определять тип переменной заранее (он определится автоматически во время выполнения программы);
  2. использовать одну переменную для хранения данных различных типов.
Пример динамической типизации

[свернуть]
Если необходимо использовать статическую типизацию, то можно использовать TypeScript или Flow.

Типы данных JavaScript

Любая константа, переменная, выражение или функция относятся к некоторому типу.

Тип данных — это категоризация аргументов операций над значениями, как правило, охватывающая как поведение, так и представление (ISO/IEC 19500-2:2003).

Тип данных определяет:

  1. допустимые значения и их смысл;
  2. операции, которые могут выполняться со значениями;
  3. способы хранения (формат представления) значений типа в памяти компьютера.

Стандарт ECMAScript определяет 7 типов данных:

  1. Примитивы:
    • Number (Число) - числовой тип данных в формате 64-битного числа двойной точности (как целочисленные, так и с плавающей запятой, а также NaN);
    • String (Строка) - последовательность символов, используемых для представления текста (в JavaScript посимвольно не корректируются, пересоздаются только полностью);
    • Boolean (Булев, Логический тип) - тип данных, которые могут принимать два возможных значения (ИСТИНА (true) и ЛОЖЬ (false);
    • Null (Null тип) - указывает на некорректное свойство (значение) или отсутствующий объект; при этом от Null унаследованы все остальные Объекты, поэтому, несмотря на то, что Null возвращает примитивное значение, его тип это object;
    • Undefined (Неопределенный тип) - автоматически присваивается объявленным переменным или аргументам, для которых не были установлены (заданы) значения (undefined можно получить при доступе к неинициализированным переменным, несуществующим свойствам объекта, несуществующим элементам массива и т.п.);
    • Symbol - примитивный тип данных, экземпляры которого уникальны и неизменяемы и могут быть использованы как ключ для свойства объекта (подробнее...).
  2. Object (Объект) - для сложных структур данных.
Подробнее о типе number

Примитивный тип данных number в JavaScript представлен числами с плавающей запятой двойной точности. Константа Number.MAX_SAFE_INTEGER содержит максимально возможное целое число (253-1), которое можно безопасно увеличить на единицу:

Любые вычисления с целыми числами вне безопасного целочисленного диапазона (т. е. от Number.MIN_SAFE_INTEGER до Number.MAX_SAFE_INTEGER) потенциально не точны. По этой причине мы можем полагаться только на целочисленные значения в безопасном диапазоне.

При необходимости хранить и обрабатывать большие целые числа даже за пределами максимального безопасного целочисленного значения Number используйте BigInt — новый числовой примитивный тип данных в JavaScript, позволяющий работать с числами произвольной точности. 

[свернуть]
Замечание по BigInt

Тип данных Большое целое (BigInt) является встроенным объектом - способом представления целых чисел, значение которых больше 253 (наибольшего числа, которое JavaScript может надежно представить с помощью примитива Number).

BigInt — новый примитивный тип данных в языке JavaScript, поэтому он получает свой собственный тип, который может вернуть оператор typeof:

Для создания BigInt достаточно добавить суффикс n к литеральной записи целого числа (например, 123 станет 123n. Глобальную функцию BigInt(number) можно использовать для приведения числа к BigInt

Пределы для безопасной работы с целыми числами не применимы к BigInt, поэтому с BigInt мы можем применять длинную арифметику не беспокоясь о потере точности.

Особенности использования BigInt:

Отсюда

Так как BigInt является самостоятельным типом данных, число типа BigInt никогда не может быть строго равно числу типа number (например, 42n !== 42). Чтобы сравнить число типа BigInt и число типа number, преобразуйте один из них в тип другого, прежде чем выполнять сравнение, или используйте сравнение с преобразованием типов (==):

При приведении к логическому значению (например, в if, при использовании && или ||, или как результат выражения Boolean(int), и так далее), числа типа BigInt ведут себя точно так же, как числа типа number:

BigInt поддерживает большинство операторов. Бинарные +, -, * и ** работают как обычно. / и % также работают, округляя результат до целого при необходимости. Побитовые операторы |, &, <<, >> и ^ работают с числами типа BigInt аналогично числам типа Number, когда отрицательные числа представлены в двоичном виде как дополнительный код.

Унарный минус ( - ) можно использовать для обозначения отрицательного значения BigInt, например, -42n. Унарный плюс ( + ) не поддерживается, потому что он нарушит код asm.js, который ожидает, что +x всегда будет возвращать либо number, либо исключение.

ВАЖНО: в операциях нельзя смешивать BigInt и number. Это хорошо, потому что любое неявное преобразование может привести к потере информации.

Рассмотрим пример:

Выброшено исключение TypeError, т.к. BigInt не может содержать дробные числа, а number не может точно содержать большие числа больше безопасного целочисленного предела. 

Операторы сравнения (=== , < и >=) к ошибке не приведут, так как они возвращают логические значения, не несущие риска потери точности:

Оператор >>>, который выполняет беззнаковый сдвиг вправо, не имеет смысла для чисел BigInt, поскольку они всегда содержат знак. Поэтому >>> не работает для чисел BigInt.

[свернуть]
Подробнее об undefined

undefined («неопределенный») представляет собой значение по умолчанию:

  • переменной, которой не было присвоено значения (т.е. объявленной, но не инициализированной);
  • функции, которая ничего не возвращает явно;
  • несуществующего свойства объекта.

Оператор typeof возвращает строку undefined для неопределенного значения:

Поэтому оператор typeof можно использовать для проверки значения undefined у переменной:

Использование const или let для неизменяемых привязок позволит снизить риски получения значения undefined при написании кода.

[свернуть]
Примеры примитивных типов данных JavaScript

Математические операции в JavaScript «безопасны». Мы можем делать что угодно: делить на ноль, обращаться со строками как с числами и т.д. Скрипт никогда не остановится с фатальной ошибкой, в худшем случае мы получим NaN.

[свернуть]
Замечание по текстовым строкам (String)

Текстовые строки (String) в JavaScript служат для представления текстовых данных. В отличие от языков подобных C, строки в JavaScript являются иммутабельными, т.е. после того как строковое значение создано, его нельзя модифицировать. Остаётся лишь создать новую строку путём совершения некой операции над исходной строкой (например, получить часть исходной строки выборкой отдельных символов, либо применением метода String.substr(), либо объединить две строки в одну, применив оператор (+) или метод String.concat()).

Целесообразно избегать повсеместного использования строк в своем коде.

Используйте строки только для текстовых данных. Для составных структур преобразуйте строки в подобающие конструкции.

[свернуть]

Возвращение (проверка) типа данных в JavaScript

Для возвращения типа объекта используется оператор typeof, который возвращает строку, указывающую тип операнда.

Проверка типа данных в JS (typeof)

[свернуть]

Объекты в JavaScript

Объект — это значение в памяти, на которое возможно сослаться с помощью идентификатора. Это таблица соотношений между ключами и значениями. Ключи — это строки (или Symbol), а значения могут быть любыми. 

В JavaScript объект может расцениваться как набор свойств. Литеральная инициализация объекта задаёт определённое количество начальных свойств, и в процессе работы приложения поля могут добавляться и удаляться. Значения свойств могут иметь любой тип, включая другие объекты, что позволяет строить сложные, разветвлённые иерархии данных. Каждое свойство объекта идентифицируется ключом, в качестве которого может выступать значение с типом Строка или Символ.

Есть два типа свойств, отличающихся определенными атрибутами:

  1. свойство-значение (ассоциирует ключ со значением);
  2. свойство-акцессор (ассоциирует ключ с одной из двух функций-акцессоров: геттер и сеттер).

Функции

Функции — это обычные объекты, имеющие дополнительную возможность быть вызванными для исполнения.

Даты

Для работы с датами служит встроенный глобальный объект Date, который основывается на значении количества миллисекунд, прошедших с 1 января 1970 года в часовом поясе UTC.

Массивы (общие и типизированные)

Массив — это обычный объект с дополнительной связью между целочисленными ключами его свойств и специальным свойством length, используемый для представления списков и перечислений.

Массивы наследуют Array.prototype, предоставляющий исчерпывающий набор методов для манипуляции массивами, например:

  • indexOf (служит для поиска значения в массиве),
  • push (добавляет элемент в конец массива) и т.д.

Типизированный массив является массиво-подобным представлением для лежащего в его основе бинарного буфера памяти, предназначенным для быстрой и эффективной работы с двоичными данными (подробнее...).

Коллекции: Maps, Sets, WeakMaps, WeakSets

Эти наборы данных используют ссылку на объект в качестве ключа:

  • Set и WeakSet являют собой набор уникальных объектов;
  • Map и WeakMap ассоциируют с объектом (выступающим в качестве ключа) некоторое значение (только у Map ключи являются перечисляемыми). 
Объект Set

Объекты Set позволяют вам сохранять уникальные значения любого типа, как примитивы, так и другие типы объектов, и представляют коллекции значений, по которым вы можете выполнить обход в порядке вставки элементов.

Все экземпляры Set унаследованы от Set.prototype.

Синтаксис

Примеры

При передаче итерируемого объекта, все его элементы будут добавлены в новый Set, иначе (или при null) новый Set будет пуст. 

Значение элемента в Set может присутствовать только в одном экземпляре, что обеспечивает его уникальность в коллекции Set.

Поскольку каждое значение в Set должно быть уникальным, сравнение значений основано на алгоритме "подобное значение":

  • NaN равно NaN (несмотря на то, что NaN !== NaN);
  • все другие значения рассматриваются равными исходя из семантики оператора строгого равенства ===.

Примеры для понимания, обход и простые операции.

Особенность работы Set со String

[свернуть]
Объект WeakSet

Объект WeakSet - коллекция, элементами которой могут быть только объекты.

Особенности WeakSet:

  1. Ссылки на объекты в WeakSet являются слабыми: если на объект, хранимый в WeakSet нет ни одной внешней ссылки, то сборщик мусора удалит этот объект.
  2. WeakSet не итерируем, так как нет возможности получить список текущих хранимых в WeakSet объектов.

Каждый объект может быть добавлен в WeakSet только один раз.

Синтаксис

При передаче итерируемого объекта, все его элементы будут добавлены в новый WeakSet.

Null обрабатывается как undefined.

Главное отличие от объекта Set:

  • WeakSet содержит только объекты, тогда как Set - значения любого типа.

Свойства и методы WeakSet

[свернуть]
Объект Map

Объект Map содержит пары ключ-значение и сохраняет порядок вставки (итерируется в порядке вставки его элементов — цикл for...of будет возвращать массив [key, value] на каждой итерации). В качестве ключей может быть использовано любое значение (как объекты, так и примитивы).

Синтаксис

В качестве параметров может быть массив или любой другой итерируемый объект, чьими элементами являются пары ключ-значение (массивы из двух элементов, например [[ 1, 'one' ],[ 2, 'two' ]]).

Все пары ключ-значение будут добавлены в новый экземпляр Map; null расценивается как undefined.

Сравнение ключей основано на алгоритме "SameValueZero":

  • NaN равно NaN (несмотря на то, что NaN !== NaN),
  • все другие значения рассматриваются равными исходя из семантики оператора строгого равенства ===.

Сравнение Object и Map:

  1. Ключами Object выступают String и Simbol, в то время как любое значение может быть ключом Map, включая функции, объекты и примитивы.
  2. В отличие от Object, ключи в Map упорядочены. Таким образом, во время итерации Map ключи возвращаются в порядке вставки. Вы легко можете получить количество элементов в Map с помощью свойства size, в то время как количество элементов Object может быть определено только вручную.
  3. Map - итерируемый объект и может быть итерирован напрямую, в то время как Object требует ручного получения списка ключей и их итерации.
  4. Object имеет прототип и поэтому имеет стандартный набор ключей, который, при неосторожности, может пересекаться с вашими ключами. С момента выхода ES5 это может быть изменено с помощью map = Object.create(null).
  5. Map может иметь более высокую производительность в случаях частого добавления или удаления ключей.

Свойства и методы Map

[свернуть]
Объект WeakMap

Объект WeakMap — коллекция пар ключ-значение. В качестве ключей могут быть использованы только объекты (примитивы в качестве ключей не допускаются, т.е. Symbol быть  ключом  не может), а значения могут быть произвольных типов.

Синтаксис

Параметр iterable может быть массивом или любым другим итерируемым объектом, элементы которого являются парами ключ-значение (массивы из двух элементов). Каждая пара ключ-значение будет добавлена во вновь созданный экземпляр WeakMap.

Null обрабатывается как undefined.

WeakMaps имеют “weak” («слабые») обращения к ключам объекта, а следовательно не мешают сборщику мусора, когда мы больше не имеем объекта-ключа. Из-за того, что ссылки являются слабыми, ключи WeakMap неперечисляемы (то есть нет метода, который возвращает список ключей). 

Свойства и методы

Все экземпляры WeakMap унаследованы от WeakMap.prototype.

[свернуть]

Объект JSON

Объект JSON

JSON (JavaScript Object Notation) — это легковесный формат обмена данными, происходящий от JavaScript, но используемый во множестве языков программирования.

JSON строит универсальные структуры данных, а также содержит методы для разбора объектной нотации JavaScript (JavaScript Object Notation — сокращённо JSON) и преобразования значений в JSON.

JSON является синтаксисом для сериализации объектов, массивов, чисел, строк логических значений и значения null.

Его нельзя вызвать как функцию или сконструировать как объект, и кроме своих двух методов он не содержит никакой интересной функциональности.

Отличия JavaScript от JSON:

  1.  Имена свойств объектов и массивов JavaScript должны быть строками, заключёнными в двойные кавычки; конечные запятые запрещены.
  2. Ведущие нули в числах запрещены; перед десятичной запятой обязательно должна быть хотя бы одна цифра.
  3. NaN и Infinity не поддерживаются.
  4. Только ограниченный набор символов может быть заэкранирован; некоторые управляющие символы запрещены; разрешены юникодные символы разделительной линии (U+2028) и разделительного параграфа (U+2029); строки должны быть заключены в двойные кавычки.

В следующем примере метод JSON.parse() работает без проблем, а при вычислении кода как JavaScript выбрасывается исключение SyntaxError:

Полный синтаскис и методы JSON

[свернуть]

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.