Символы — это примитивный тип, представленный в ES6 и используемый в качестве нестроковых имен свойств. Чтобы понимать символы, важно знать, что в JavaScript базовый тип Object
представляет собой неупорядоченную коллекцию свойств, каждое из которых имеет имя и значение. Имена свойств обычно (до ES6) были строками. Однако в ES6 и более поздних версиях символы также можно использовать в качестве имен свойств:
// String that can be used as a property name let strname = "string name"; // Symbol that can be used as a property name let symname = Symbol("propname"); //=> "string": strname is a string typeof strname //=> "symbol": symname is a symbol typeof symname // Create a new object let o = {}; // Define a property with a string name o[strname] = 1; // Define a property with a symbol name o[symname] = 2; //=> 1: Access property with string name o[strname] // => 2: Access property with symbol name o[symname]
Символы не имеют буквального синтаксиса. Чтобы получить значение символа, необходимо вызвать функцию Symbol()
. Эта функция никогда не возвращает одно и то же значение, даже если вы каждый раз предоставляете один и тот же аргумент. Это означает, что вы можете безопасно использовать результат вызова Symbol()
для добавления новых свойств к объекту, не беспокоясь о перезаписи существующих свойств с тем же именем. Аналогично, если вы определяете свойство символа и не публикуете соответствующий символ, вы можете быть уверены, что другие части вашего кода не перезапишут случайно это свойство.
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)
На практике символы часто используются как механизм расширений языка. В ES6 появился цикл for/of
и концепция итерируемых объектов, что требовало определения стандартизированного способа, с помощью которого классы могут сделать себя итерируемыми. Однако использование какой-либо конкретной строки в качестве имени этого метода итератора потенциально может привести к конфликту с существующим кодом. Здесь в игру вступают символы. Symbol.iterator
— это значение символа, которое можно использовать в качестве имени метода, чтобы сделать объект итерируемым.
Функция Symbol()
опционально принимает строковый параметр и возвращает уникальное значение символа. Если вы предоставите строковый параметр, результат вызова метода toString()
для возвращаемого значения символа будет включать эту строку. Однако важно отметить, что двойной вызов Symbol()
с одной и той же строкой приведет к получению двух совершенно разных значений символов.
let s = Symbol("syn_x"); // => "Symbol(syn_x)" s.toString()
Единственный интересный метод для значений символов — toString()
. Однако есть еще две функции, связанные с символами, о которых стоит знать. Иногда при использовании символов вы хотите, чтобы они были закрытыми для вашего кода, чтобы гарантировать, что ваши свойства не будут конфликтовать со свойствами из другого кода. Но в других случаях вам может потребоваться определить символы, которые можно использовать совместно с другим кодом. Например, если вы определяете расширение и хотите, чтобы его использовал другой код, аналогично механизму Symbol.iterator
, упомянутому ранее.
Чтобы определить символы, которые могут использоваться совместно с другим кодом, в JavaScript имеется глобальный реестр символов. Функция Symbol.for()
принимает строковый параметр и возвращает значение символа, связанное с этой строкой. Если со строкой не связан ни один символ, будет создан и возвращен новый символ; в противном случае он вернет существующий символ. Другими словами, Symbol.for()
и Symbol()
совершенно разные: Symbol()
никогда не возвращает одно и то же значение, а Symbol.for()
всегда возвращает одно и то же значение при вызове с одной и той же строкой. Строка, предоставленная Symbol.for()
, появится в выходных данных toString()
(при возврате значения символа). Кроме того, эту строку можно получить с помощью Symbol.keyFor()
, передав возвращаемый символ:
let s = Symbol.for("shared"); let t = Symbol.for("shared"); // => true s === t // => "Symbol(shared)" s.toString() // "shared" Symbol.keyFor(t)
(Мягкие навыки для программистов: amazon.com/dp/B0CF599P8J)