В ES6 появился новый достаточно специфичный тип данных, именуемый Symbol. Он служит для создания уникальных идентификаторов.
Как правило он используется при работе с объектами, когда нам необходимо создать уникальное свойство не доступное в открытом виде (скрытое).
Пример создания:
let sym = Symbol("myname");
Важно обратить внимание, что используется не new Symbol, а просто Symbol. Дело в том, что это не конструктор и использование оператора new невозможно.
Так же при объявлении, мы использовали строковый параметр myname, который не обязателен. Он используется для отладки и по нему нельзя обратиться.
Для более полного понимания давайте рассмотрим принцип работы с Symbol в JavaScript на примере.
Для начала создадим новый объект:
let obj = {
name: "Вася",
surename: "Васечкин",
age: 27
}
Теперь, что бы обратиться к свойству name мы можем воспользоваться одним и следующих методов:
console.log(obj.name) // "Вася"
//или
console.log(obj["name"]) // "Вася"
Но, что если нам это свойство необходимо использовать как системное и мы не хотим, что бы оно было доступно в открытом виде.
И тут на помощь приходит новый тип данных symbol
//создаем символ в реестре
let name = Symbol();
let obj = {
[name]: "Вася",
surename: "Васечкин",
age: 27,
}
Особенность такой записи, дает нам возможность запретить обращение к свойству name через строковый литерал. И если мы попытаемся обратиться к нему как в ранее приведенных примерах, то вместо значения «Вася», у нас будет выведено в консоль undefined
console.log(obj.name) // "undefined"
//или
console.log(obj["name"]) // "undefined"
Но если мы к нему обратимся по ранее созданному символу name, то получим необходимое значение
console.log(obj[name]) // "Вася"
Тем самым мы скрыли это свойство и сделали его уникальным по значению именно символа.
Так же это свойство не будет доступно в цикле перечисления объекта
for (let key in obj) {
console.log(key);
}
//будут выведены только ключи age и surename. Ключ-символ name будет пропущен
Также его не будет видно через методы Object.keys() и Object.getOwnPropertyNames()
console.log( Object.keys(obj)); // [ "surename", "age"]
console.log( Object.getOwnPropertyNames(obj)); // [ "surename", "age"]
Что бы получить символьные свойства объекта, можно воспользоваться методом Object.getOwnPropertySymbols()
console.log( Object.getOwnPropertySymbols(obj)); // [Symbol()]
Из этого можно сделать вывод, что символьные свойства не являются скрытыми, так как их всегда можно увидеть с помощью метода Object.getOwnPropertySymbols()
Реестр символов
Если нам нужно, что бы символ находился в глобальной области видимости и был доступен для всех частей кода, то его следует создать в глобальном реестре (global symbol registry) с помощью метода Symbol.for()
let s = Symbol.for("some symbol");
Он проверяет наличие данного символа с этим описанием в реестре, если такой имеется, то он возвращает его, в противном случае создает.
Получить ключ описание зарегистрированного символа можно используя метод Symbol.keyFor()
let key = Symbol.keyFor(s);
console.log(key); //"some symbol"
Метод Symbol.keyFor() работает только с глобальными символами, если при работе с ним используется не глобально созданный символ, то значение будет навно undefined
Важно понимать, что что значение символа уникально
var a = Symbol('name');
var b = Symbol('name');
console.log(a === b); //false
Это позволяет нам не беспокоится за возможные конфликты имен. И если нам все таки нужен один и тот же символ в разных местах кода, то его можно объявить один раз в глобальном реестре символов.
Наверное, самое широкое применение символов используется внутри самого JavaScript. В ES6 уже используются встроенные символы, которые влияют на поведение различных объектов.Они находятся не в глобальном реестре и хранятся как свойства объекта-функции Symbol.