что означает в javascript символ

Особенности использования типа данных Symbol в JavaScript

Символьные примитивы — это одно из новшеств стандарта ES6, которое принесло в JavaScript некоторые ценные возможности. Символы, представленные типом данных Symbol, особенно полезны при использовании их в качестве идентификаторов свойств объектов. В связи с таким сценарием их применения напрашивается вопрос о том, что такого они могут, чего не могут строки.

что означает в javascript символ. Смотреть фото что означает в javascript символ. Смотреть картинку что означает в javascript символ. Картинка про что означает в javascript символ. Фото что означает в javascript символ

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

Предварительные сведения

Примитивные значения иммутабельны. Их нельзя изменять. Конечно, в переменную, хранящую примитивное значение, можно записать что-то новое. Например, здесь выполняется запись нового значения в переменную x :

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

Рассмотрим следующий пример:

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

Объекты играют фундаментальную роль в JavaScript. Они применяются буквально повсюду. Например, часто их используют в виде коллекций вида ключ/значение. Но до появления типа данных Symbol в качестве ключей объектов можно было применять лишь строки. В этом крылось серьёзное ограничение использования объектов в виде коллекций. При попытке назначения нестрокового значения в виде ключа объекта это значение приводилось к строке. Убедиться в этом можно так:

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

Что такое символ?

Теперь, когда мы выяснили особенности примитивных значений в JavaScript, мы наконец готовы к тому, чтобы приступить к разговору о символах. Символ — это уникальное примитивное значение. Если подходить к символам с этой позиции, то можно заметить, что символы в этом плане похожи на объекты, так как создание нескольких экземпляров символов приведёт к созданию разных значений. Но символы, кроме того, являются иммутабельными примитивными значениями. Вот пример работы с символами:

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

Символы как ключи свойств объектов

Символы можно использовать в качестве ключей свойств объектов. Это очень важно. Вот пример использования их в таком качестве:

На первый взгляд может показаться, что вышеописанные особенности символов позволяют использовать их для создания приватных свойств JS-объектов. Во многих других языках программирования можно создавать скрытые свойства объектов с использованием классов. Отсутствие этой возможности уже давно считается одним из недостатков JavaScript.

К сожалению, код, который работает с объектами, может беспрепятственно обращаться к их строковым ключам. Код может обращаться и к ключам, заданным символами, причём, даже в том случае, если у кода, из которого работают с объектом, нет доступа к соответствующему символу. Например, с помощью метода Reflect.ownKeys() можно получить список всех ключей объекта, и тех, что являются строками, и тех, что являются символами:

Обратите внимание на то, что в настоящее время ведётся работа над тем, чтобы оснастить классы возможностью использования приватных свойств. Эта возможность называется Private Fields (приватные поля). Она, правда, не затрагивает абсолютно все объекты, относясь лишь к тем из них, которые созданы на основе предварительно подготовленных классов. Поддержка приватных полей уже имеется в браузере Chrome версии 72 и старше.

Предотвращение коллизий имён свойств объектов

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

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

Именно глядя на подобный сценарий можно ощутить пользу от появления символов в JavaScript.

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

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

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

Если бы в этой ситуации для имени ключа использовался бы символ, тогда JSON-представление объекта не содержало бы значения символа. Почему это так? Дело в том, что то, что в JavaScript появился новый тип данных, ещё не означает того, что изменения внесены и в спецификацию JSON. JSON поддерживает, в качестве ключей свойств объектов, только строки. При сериализации объекта не делается попыток представить символы в каком-то особом виде.

Рассматриваемую проблему попадания имён свойств в JSON-представление объектов можно решить благодаря использованию Object.defineProperty() :

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

Имитация приватных свойств

Вот интересный подход, который можно использовать для имитации приватных свойств объектов. Этот подход предусматривает применение ещё одной современной возможности JavaScript — прокси-объектов. Такие объекты служат обёртками для других объектов, которые позволяют программисту вмешиваться в действия, выполняемые с этими объектами.

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

Тут надо отметить, что в Node.js есть одна особенность, нарушающая приватность прокси-объектов. Эта особенность не существует в самом языке, поэтому она не актуальна для других сред выполнения JS, таких, как браузер. Дело в том, что эта особенность позволяет получать доступ к объекту, скрытому за прокси-объектом, при наличии доступа к прокси-объекту. Вот пример, демонстрирующий возможность обхода механизмов, показанных в предыдущем фрагменте кода:

Итоги

Уважаемые читатели! Пользуетесь ли вы символами в своих JavaScript-проектах?

Источник

Тип данных Symbol

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

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

Символы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Symbol.keyFor

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

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

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

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

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

Итого

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

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

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

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

Источник

Выражения и операторы

Эта глава описывает выражения и операторы языка JavaScript, такие как операторы присваивания, сравнения, арифметические, битовые, логические, строчные, и различные специальные операторы.

Полный и детальный список операторов и выражений также доступен в этом руководстве.

Операторы

В JavaScript есть следующие типы операторов. Данный подраздел описывает каждый тип и содержит информацию об их приоритетах друг над другом.

В свою очередь унарная операция использует один операнд, перед или после оператора:

Операторы присваивания

Существуют также составные операторы присваивания, которые используются для сокращённого представления операций, описанных в следующей таблице:

Деструктуризация

Операторы сравнения

Замечание: (=>) не оператор, а нотация Стрелочных функций.

Арифметические операторы

Арифметические операторы (en-US) используют в качестве своих операндов числа (также литералы или переменные) и в качестве результата возвращают одно числовое значение. Стандартными арифметическими операторами являются сложение (+), вычитание (-), умножение (*), и деление (/). При работе с числами с плавающей точкой эти операторы работают аналогично их работе в большинстве других языках программирования (обратите внимание, что деление на ноль возвращает бесконечность Infinity ). Например:

Кроме того, JavaScript позволяет использовать следующие арифметические операторы, представленные в таблице:

Битовые (поразрядные) операторы

Битовые операторы (en-US) обрабатывают свои операнды как последовательности из 32 бит (нулей и единиц), а не как десятичные, шестнадцатеричные или восьмеричные числа. Например, десятичное число 9 имеет двоичное представление 1001. Битовые операторы выполняют операции над таким двоичным представлением, но результат возвращают как обычное числовое значение JavaScript.

Следующая таблица обобщает битовые операторы JavaScript.

Битовые операторы

a

ОператорИспользованиеОписание
Побитовое И (en-US)a & bВозвращает единицу в каждой битовой позиции, для которой соответствующие биты обеих операндов являются единицами.
Побитовое ИЛИ (en-US)a | bВозвращает единицу в каждой битовой позиции, для которой один из соответствующих битов или оба бита операндов являются единицами.
Исключающее ИЛИ (en-US)a ^ bВозвращает единицу в каждой битовой позиции, для которой только один из соответствующих битов операндов является единицей.
Побитовое НЕ (en-US)Заменяет биты операнда на противоположные.
Сдвиг влево (en-US)aСдвигает a в двоичном представлении на b бит влево, добавляя справа нули.
Сдвиг вправо с переносом знака (en-US)a >> bСдвигает a в двоичном представлении на b бит вправо, отбрасывая сдвигаемые биты.
Сдвиг вправо с заполнением нулями (en-US)a >>> bСдвигает a в двоичном представлении на b бит вправо, отбрасывая сдвигаемые биты и добавляя слева нули.

Битовые логические операторы

Основной смысл работы битовых логических операторов состоит в следующем:

Примеры работы битовых операторов

Обратите внимание, что все 32 бита преобразуются с использованием битового оператора НЕ, и что величины с наиболее значимым (самым левым) битом равным 1 представляют собой отрицательные числа (в представлении дополнения до двух).

Битовые операторы сдвига

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

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

Операторы сдвига перечислены в следующей таблице.

Логические операторы

Логические операторы (en-US) обычно используются с булевыми (логическими) значениями; при этом возвращаемое ими значение также является булевым. Однако операторы && и || фактически возвращают значение одного из операндов, поэтому, если эти операторы используются с небулевыми величинами, то возвращаемая ими величина также может быть не булевой. Логические операторы описаны в следующей таблице.

Примерами выражений, которые могут быть преобразованы в false являются: null, 0, NaN, пустая строка («») или undefined.

Следующий код демонстрирует примеры использования оператора && (логическое И).

Следующий код демонстрирует примеры использования оператора || (логическое ИЛИ).

Сокращённая оценка

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

Правила логики гарантируют, что данные вычисления всегда корректны. Обратите внимание, что часть «anything» представленных выше выражений не вычисляется, таким образом удаётся избежать любых побочных эффектов вычисления данной части.

Строковые операторы

В дополнение к операторам сравнения, которые могут использоваться со строковыми значениями, оператор (+) позволяет объединить две строки, возвращая при этом третью строку, которая представляет собой объединение двух строк-операндов:

Сокращённый оператор присваивания += также может быть использован для объединения (конкатенации) строк:

Условный (тернарный) оператор

Условный оператор является единственным оператором JavaScript, который использует три операнда. Оператор принимает одно из двух значений в зависимости от заданного условия. Синтаксис оператора:

val1 и val2 обязательно должны что-то возвращать, поэтому в этой конструкции нельзя использовать continue или break

Оператор запятая

Например, если a является двумерным массивом, каждая строка которого содержит 10 элементов, то следующий код с использованием оператора запятая позволяет выполнять одновременное приращение двух переменных. Данный код выводит на экран значения диагональных элементов массива:

Унарные операторы

delete

Оператор delete выполняет удаление объекта, свойства объекта, или элемента массива с заданным индексом. Синтаксис оператора:

Удаление элементов массива

Оператор typeof

Оператор typeof используется одним из следующих способов:

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

Предположим, вы определяете следующие переменные:

Оператор typeof возвращает следующие результаты для этих переменных:

Для дескрипторов true и null оператор typeof возвращает следующие результаты:

Для чисел и строк оператор typeof возвращает следующие результаты:

Для свойств оператор typeof возвращает тип значения данного свойства:

Для методов и функций оператор typeof возвращает следующие результаты:

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

Оператор void

Оператор void используется любым из следующих способов:

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

Приведённый ниже код создаёт гипертекстовую ссылку, которая подтверждает отправку формы при клике на ней пользователем:

Операторы отношения

Оператор отношения сравнивает свои операнды и возвращает результат сравнения в виде булева значения.

Оператор in

Оператор in возвращает true, если указанный объект имеет указанное свойство. Синтаксис оператора:

Некоторые примеры способов использования оператора in :

Оператор instanceof

Оператор instanceof возвращает true, если заданный объект является объектом указанного типа. Его синтаксис:

Приоритет операторов

Приоритет операторов определяет порядок их выполнения при вычислении выражения. Вы можете влиять на приоритет операторов с помощью скобок.

Приведённая ниже таблица описывает приоритет операторов от наивысшего до низшего.

ВыражениеРезультатДвоичное описание
15 & 991111 & 1001 = 1001
15 | 9151111 | 1001 = 1111
15 ^ 961111 ^ 1001 = 0110
Таблица 3.7 Приоритет операторов

Тип оператораОператоры
свойство объекта. []
вызов, создание экземпляра объекта() new
отрицание, инкремент!

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

Выражения

Выражением является любой корректный блок кода, который возвращает значение.

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

Код 3 + 4 является примером выражения второго типа. Данное выражение использует оператор «+» для сложения чисел 3 и 4 без присваивания переменной полученного результата 7.

Все выражения в JavaScript делятся на следующие категории:

Основные выражения

Базовые ключевые слова и основные выражения в JavaScript.

Оператор this

Используйте ключевое слово this для указания на текущий объект. В общем случае this указывает на вызываемый объект, которому принадлежит данный метод. Используйте this следующим образом:

Предположим, функция validate выполняет проверку свойства value некоторого объекта; задан объект, а также верхняя и нижняя граница величины данного свойства:

Вы можете вызвать функцию validate для обработчика события onChange для каждого элемента формы, используя this для указания на элемент формы, как это показано в следующем примере:

Оператор группировки

Упрощённый синтаксис создания массивов и генераторов

[for (x of y) x] Упрощённый синтаксис для массивов. (for (x of y) y) Упрощённый синтаксис для генераторов.

Упрощённые синтаксисы существуют во многих языках программирования и позволяют вам быстро собирать новый массив, основанный на существующем. Например:

Левосторонние выражения

Значениям слева назначаются значения справа.

Вы можете использовать оператор new для создания экземпляра объекта пользовательского типа или одного из встроенных объектов. Используйте оператор new следующим образом:

super

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

Оператор расширения

Оператор расширения позволяет выражению расширяться в местах с множеством аргументов (для вызовов функций) или множестве элементов (для массивов).

Похожим образом оператор работает с вызовами функций:

Источник

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *