Что значить тип данных символьный

Тип данных Symbol

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

До сих пор мы видели только строки. Теперь давайте разберём символы, увидим, что хорошего они нам дают.

Символы

«Символ» представляет собой уникальный идентификатор.

Создаются новые символы с помощью функции Symbol() :

При создании символу можно дать описание (также называемое имя), в основном использующееся для отладки кода:

Символы гарантированно уникальны. Даже если мы создадим множество символов с одинаковым описанием, это всё равно будут разные символы. Описание – это просто метка, которая ни на что не влияет.

Например, вот два символа с одинаковым описанием – но они не равны:

Если вы знаете Ruby или какой-то другой язык программирования, в котором есть своего рода «символы» – пожалуйста, будьте внимательны. Символы в JavaScript имеют свои особенности, и не стоит думать о них, как о символах в Ruby или в других языках.

Большинство типов данных в JavaScript могут быть неявно преобразованы в строку. Например, функция alert принимает практически любое значение, автоматически преобразовывает его в строку, а затем выводит это значение, не сообщая об ошибке. Символы же особенные и не преобразуются автоматически.

К примеру, alert ниже выдаст ошибку:

Это – языковая «защита» от путаницы, ведь строки и символы – принципиально разные типы данных и не должны неконтролируемо преобразовываться друг в друга.

Если же мы действительно хотим вывести символ с помощью alert , то необходимо явно преобразовать его с помощью метода .toString() , вот так:

Или мы можем обратиться к свойству symbol.description , чтобы вывести только описание:

«Скрытые» свойства

Символы позволяют создавать «скрытые» свойства объектов, к которым нельзя нечаянно обратиться и перезаписать их из других частей программы.

Например, мы работаем с объектами user , которые принадлежат стороннему коду. Мы хотим добавить к ним идентификаторы.

Используем для этого символьный ключ:

Почему же лучше использовать Symbol(«id») , а не строку «id» ?

Так как объект user принадлежит стороннему коду, и этот код также работает с ним, то нам не следует добавлять к нему какие-либо поля. Это небезопасно. Но к символу сложно нечаянно обратиться, сторонний код вряд ли его вообще увидит, и, скорее всего, добавление поля к объекту не вызовет никаких проблем.

Кроме того, предположим, что другой скрипт для каких-то своих целей хочет записать собственный идентификатор в объект user . Этот скрипт может быть какой-то JavaScript-библиотекой, абсолютно не связанной с нашим скриптом.

Сторонний код может создать для этого свой символ Symbol(«id») :

Конфликта между их и нашим идентификатором не будет, так как символы всегда уникальны, даже если их имена совпадают.

А вот если бы мы использовали строку «id» вместо символа, то тогда был бы конфликт:

Символы в литеральном объекте

Если мы хотим использовать символ при литеральном объявлении объекта <. >, его необходимо заключить в квадратные скобки.

Это вызвано тем, что нам нужно использовать значение переменной id в качестве ключа, а не строку «id».

Символы игнорируются циклом for…in

Свойства, чьи ключи – символы, не перебираются циклом for..in .

Это – часть общего принципа «сокрытия символьных свойств». Если другая библиотека или скрипт будут работать с нашим объектом, то при переборе они не получат ненароком наше символьное свойство. Object.keys(user) также игнорирует символы.

А вот Object.assign, в отличие от цикла for..in , копирует и строковые, и символьные свойства:

Здесь нет никакого парадокса или противоречия. Так и задумано. Идея заключается в том, что, когда мы клонируем или объединяем объекты, мы обычно хотим скопировать все свойства (включая такие свойства с ключами-символами, как, например, id в примере выше).

Глобальные символы

Итак, как мы видели, обычно все символы уникальны, даже если их имена совпадают. Но иногда мы наоборот хотим, чтобы символы с одинаковыми именами были одной сущностью. Например, разные части нашего приложения хотят получить доступ к символу «id» , подразумевая именно одно и то же свойство.

Для этого существует глобальный реестр символов. Мы можем создавать в нём символы и обращаться к ним позже, и при каждом обращении нам гарантированно будет возвращаться один и тот же символ.

Для чтения (или, при отсутствии, создания) символа из реестра используется вызов Symbol.for(key) .

Он проверяет глобальный реестр и, при наличии в нём символа с именем key , возвращает его, иначе же создаётся новый символ Symbol(key) и записывается в реестр под ключом key .

Символы, содержащиеся в реестре, называются глобальными символами. Если вам нужен символ, доступный везде в коде – используйте глобальные символы.

В некоторых языках программирования, например, Ruby, на одно имя (описание) приходится один символ, и не могут существовать разные символы с одинаковым именем.

В JavaScript, как мы видим, это утверждение верно только для глобальных символов.

Symbol.keyFor

Для глобальных символов, кроме Symbol.for(key) , который ищет символ по имени, существует обратный метод: Symbol.keyFor(sym) , который, наоборот, принимает глобальный символ и возвращает его имя.

Внутри метода Symbol.keyFor используется глобальный реестр символов для нахождения имени символа. Так что этот метод не будет работать для неглобальных символов. Если символ неглобальный, метод не сможет его найти и вернёт undefined .

Впрочем, для любых символов доступно свойство description .

Системные символы

Существует множество «системных» символов, использующихся внутри самого JavaScript, и мы можем использовать их, чтобы настраивать различные аспекты поведения объектов.

Эти символы перечислены в спецификации в таблице Well-known symbols:

  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.toPrimitive
  • …и так далее.

В частности, Symbol.toPrimitive позволяет описать правила для объекта, согласно которым он будет преобразовываться к примитиву. Мы скоро увидим его применение.

С другими системными символами мы тоже скоро познакомимся, когда будем изучать соответствующие возможности языка.

Итого

Символ (symbol) – примитивный тип данных, использующийся для создания уникальных идентификаторов.

Символы создаются вызовом функции Symbol() , в которую можно передать описание (имя) символа.

Даже если символы имеют одно и то же имя, это – разные символы. Если мы хотим, чтобы одноимённые символы были равны, то следует использовать глобальный реестр: вызов Symbol.for(key) возвращает (или создаёт) глобальный символ с key в качестве имени. Многократные вызовы команды Symbol.for с одним и тем же аргументом возвращают один и тот же символ.

Символы имеют два основных варианта использования:

«Скрытые» свойства объектов. Если мы хотим добавить свойство в объект, который «принадлежит» другому скрипту или библиотеке, мы можем создать символ и использовать его в качестве ключа. Символьное свойство не появится в for..in , так что оно не будет нечаянно обработано вместе с другими. Также оно не будет модифицировано прямым обращением, так как другой скрипт не знает о нашем символе. Таким образом, свойство будет защищено от случайной перезаписи или использования.

Так что, используя символьные свойства, мы можем спрятать что-то нужное нам, но что другие видеть не должны.

Источник

Структура языка программирования

Содержание

Дополнительно

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

Классификация типов данных

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

Числовой тип данных разработан для хранения естественно чисел. Символьный — для хранения одного символа. Логический тип имеет два значения: истина и ложь. Перечислимый тип может хранить только те значения, которые прямо указаны в его описании.

Для простых типов данных определяются границы диапазона и количество байт, занимаемых ими в памяти компьютера.

В большинстве языков программирования, простые типы жестко связаны с их представлением в памяти компьютера. Компьютер хранит данные в виде последовательности битов, каждый из которых может иметь значение 0 и 1. Фрагмент данных в памяти может выглядеть следующим образом

Данные на битовом уровне (в памяти) не имеют ни структуры, ни смысла. Как интерпретировать данные, как целочисленное число, или вещественное, или символ, зависит от того, какой тип имеют данные, представленные в этой и последующих ячейках памяти.

Числовые типы данных

Целочисленные типы данных

Выделяют знаковые и беззнаковые. Как видно из названия, знаковые предназначены для хранения как положительных, так и отрицательных значений, нуль, а беззнаковые — чисел, не меньше нуля.

Беззнаковые типы данных, в отличии от соответствующих знаковых, имеют в два раза больший диапазон. Это из-за их машинного представления. В знаковых типах первый бит указывает на знак числа: 1 — отрицательное, 0 — положительное.

Исходя из машинного представления целого числа, в ячейке памяти из n бит может хранится 2 n для беззнаковых, и 2 n-1 для знаковых типов.

Рассмотрим теперь конкретные целочисленные типы в трёх языках.

Тип Разрядность в битах Диапазон чисел
byte 8 0 — 255
sbyte 8 -128 — 127
short 16 -32 768 — 32 767
ushort 16 0 — 65 535
int 32 -2 147 483 648 — 2 147 483 647
uint 32 0 — 4 294 967 295
long 64 -9 223 372 036 854 775 808 — 9 223 372 036 854 775 807
ulong 64 0 — 18 446 744 073 709 551 615
Тип Разрядность в битах Диапазон чисел
unsigned short int / unsigned short 16 0 — 65 535
short int 16 -32 768 — 32 767
unsigned long int / unsigned long 32 0 — 4 294 967 295
long int / long 32 -2 147 483 648 — 2 147 483 647
int (16 разрядов) 16 -32 768 — 32 767
int (32 разряда) 32 -2 147 483 648 — 2 147 483 647
unsigned int (16 разрядов) 16 0 — 65 535
unsigned int (32 разряда) 32 0 — 4 294 967 295

У некоторых типов есть приписка «16 разрядов» или «32 разряда». Это означает, что в зависимости от разрядности операционной системы и компилятора данный тип будет находится в соответствующем диапазоне. По-этому, рекомендуется не использовать int, unsigned int, а использовать их аналоги, но уже жестко определенные, short, long, unsigned short, unsigned long.

Тип Разрядность в битах Диапазон чисел
byte 8 -128 — 127
short 16 -32 768 — 32 767
int 32 -2 147 483 648 — 2 147 483 647
long 64 -9 223 372 036 854 775 808 — 9 223 372 036 854 775 807

В Java нет беззнаковых целочисленных типов данных.

Вещественные типы данных

Числа вещественного типа данных задаются в форме чисел с плавающей запятой.

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

где N — записываемое число;
M — мантисса;
p (целое) — порядок.
Например: 14441544=1,4441544*10 7 ; 0,0004785=4,785*10 -4 . Компьютер же на экран выведет следующие числа:

Следовательно, в отведенной памяти хранится мантисса и порядок записываемого числа. Рассмотрим на примера типа данных, который хранится в 8 байтах или 64 битах. В данном случае, мантисса составляет 53 бита: 1 для знака числа и 52 для её значения; порядок 10 битов: 1 бит для знака и 10 для значения. Мы можем в данном случае говорить о диапазоне точности, то есть насколько малое и насколько большое число может хранить данный тип данных: 4,94×10 −324 до 1.79×10 308 . Но, поскольку, память компьютера не безразмерна, да и далеко не всегда нужно, храниться несколько первых разрядов мантиссы, которые называются значащими.

Вывод: вещественные типы данных, в отличии от целочисленных, характеризуются диапазоном точности и количеством значащих разрядов.

Рассмотрим конкретные типы данных в наших трёх языках.

Тип Разрядность в битах Количество значащих цифр Диапазон точности
float 32 7 от 1,5*10 -45 до 3,4*10 38
double 64 15 от 4,9*10 -324 до 1,7*10 308
decimal 128 28 от 1,0*10 -28 до 7,9*10 28

Тип decimal создан специально для операций высокой точности, в частности финансовых операций. Он не реализован как примитивный тип, по-этому его частое использование может повлиять на производительность вычислений.

Тип Разрядность в битах Количество значащих цифр Диапазон точности
float 32 7 от 1,5*10 -45 до 3,4*10 38
double 64 15 от 4,9*10 -324 до 1,7*10 308
Тип Разрядность в битах Количество значащих цифр Диапазон точности
float 32 7 от 1,5*10 -45 до 3,4*10 38
double 64 15 от 4,9*10 -324 до 1,7*10 308

Символьный тип данных

Значение переменной этого типа данных представляет собой один символ. В действительности, это есть целое число. В зависимости от кодировки, это число превращается в некий символ. Данные типы данных характеризуются лишь размером выделяемой под них памяти.

Тип Разрядность в битах
char 16
Тип Разрядность в битах
char 8
wchar_t 16
Тип Разрядность в битах
char 16

Логический тип данных

Это тип данных, значения которых могут быть: true (правда) или false (ложь). Логическому типу данных соответствуют в С# и C++ тип bool, в Java — boolean.

Перечислимый тип данных

Во внутреннем представлении, это целочисленный тип данных, только здесь пользователь вместо числе использует заранее определенные строковые значения.

Чтобы прочувствовать эту концепцию, приведем пример на языке С++ (в С# и Java аналогично)

Теперь переменные перечислимого типа Forms могут принимать лишь значения, определенные в примере кода. Это очень удобно, ведь мы уже оперируем не с числами, а с некими смысловыми значениями, замечу лишь, что для компьютера эти значения всё-равно являются целыми числами.

Массив

Далее перейдем к сложным типам данных. Первый из них — это массив. Массив — это набор однотипных переменных, расположенных в памяти непосредственно друг за другом, доступ к которым осуществляется по индексу. Индекс массива — целое число, указывающее на конкретный элемент массива.

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

В языках программирования нельзя оперировать всем массивом, работают с конкретным элементом. Чтобы доступиться до него в трёх рассматриваемых нами языках используют оператор «[]».

Структура

Ранее были рассмотрены встроенные типы данных. Теперь мы переходим к пользовательским типам данных. Структура — конструкция, позволяющая содержать в себе набор переменных различных типов.

Структуры реализованы в языке программирования, чтобы собрать некие близки по смыслу вещи воедино.

Например, есть колесо автомобиля. У колеса есть диаметр, толщина, шина. Шина в свою очередь является структурой, у которой есть свои параметры: материал, марка, чем заполнена. Естественно, для каждого параметра можно создать свою переменную или константу, у нас появится большое количество переменных, которые, чтобы понять к чему они относятся, нужно в именах общую часть выделять. Имена будут нести лишнюю смысловую нагрузку. Получается запутанная история. А так мы определяем две структуры, а затем параметры в них.

Класс

Еще одним пользовательским типом данных является класс. Класс умеет всё, что и структура, но кроме параметров, у него есть и методы, и поддерживает большое количество вещей, связанных с объектно-ориентированным программированием.

Источник

Читайте также:  Что значит с постоянной по модулю скоростью
Оцените статью