Символы можно использовать в качестве имён для свойств объекта следующим образом:
'use strict';
let isAdmin = Symbol("isAdmin");
let user = { name: "Вася", [isAdmin]: true
};
alert(user[isAdmin]); // true
Особенность символов в том, что если в объект записать свойство‑символ, то оно не участвует в итерации:
'use strict';
let user = { name: "Вася", age: 30,
[Symbol.for("isAdmin")]: true
};
// в цикле for..in также не будет символа alert( Object.keys(user) ); // name, age
// доступ к свойству через глобальный символ — работает alert( user[Symbol.for("isAdmin")] );
Кроме того, свойство‑символ недоступно, если обратиться к его названию: user.isAdmin не существует. Зачем всё это, почему просто не использовать строки?
Резонный вопрос. На ум могут прийти соображения производительности, так как символы – это по сути специальные идентификаторы, они компактнее, чем строка. Но при современных оптимизациях объектов это редко имеет значение.
Самое широкое применение символов предусмотрено внутри самого стандарта JavaScript. В современном стандарте есть много системных символов. Их список есть в спецификации, в таблице Well‑known Symbols . В спецификации для краткости символы принято обозначать как „@@имя“, например @@iterator , но доступны они как свойства Symbol .
Например:
Symbol.toPrimitive – идентификатор для свойства, задающего функцию преобразования объекта в примитив.
Symbol.iterator – идентификатор для свойства, задающего функцию итерации по объекту.
…и т.п.
Мы легко поймём смысл введения нового типа «символ», если поставим себя на место создателей языка JavaScript.
Допустим, в новом стандарте нам надо добавить к объекту «особый» функционал, например, функцию, которая задаёт преобразование объекта к примитиву. Как obj.toString , но для преобразования в примитивы.
Мы ведь не можем просто сказать, что «свойство obj.toPrimitive теперь будет задавать преобразование к примитиву и автоматически вызываться в таких‑то ситуациях». Это опасно. Мы не можем так просто взять и придать особый смысл свойству. Мало ли, вполне возможно, что свойство с таким именем уже используется в существующем коде, и если сделать его особым, то он сломается.
Нельзя просто взять и зарезервировать какие‑то свойства существующих объектов для нового функционала. Поэтому ввели целый тип «символы». Их можно использовать для задания таких свойств, так как они:
а) уникальны,
б) не участвуют в циклах,
в) заведомо не сломают старый код, который о них слыхом не слыхивал.
Продемонстрируем отсутствие конфликта для нового системного свойства Symbol.iterator :
'use strict';
let obj = { iterator: 1,
[Symbol.iterator]() {}
}
alert(obj.iterator); // 1
alert(obj[Symbol.iterator]) // function, символ не конфликтует
Выше мы использовали системный символ Symbol.iterator , поскольку он один из самых широко поддерживаемых. Мы подробно разберём его смысл в главе про итераторы, пока же – это просто пример символа.
Чтобы получить все символы объекта, есть особый вызов Object.getOwnPropertySymbols .
Эта функция возвращает все символы в объекте (и только их). Заметим, что старая функция getOwnPropertyNames символы не возвращает, что опять же гарантирует отсутствие конфликтов со старым кодом.
'use strict';
let obj = { iterator: 1,
[Symbol.iterator]: function() {}
}
// один символ в объекте
alert( Object.getOwnPropertySymbols(obj) ); // Symbol(Symbol.iterator)
// и одно обычное свойство
alert( Object.getOwnPropertyNames(obj) ); // iterator
Итого
Символы – новый примитивный тип, предназначенный для уникальных идентификаторов.
Все символы уникальны. Символы с одинаковым именем не равны друг другу.
Существует глобальный реестр символов, доступных через метод Symbol.for(name) . Для глобального символа можно получить имя вызовом и
Symbol.keyFor(sym) .
Основная область использования символов – это системные свойства объектов, которые задают разные аспекты их поведения. Поддержка у них пока небольшая, но она растёт. Системные символы позволяют разработчикам стандарта добавлять новые «особые» свойства объектов, при этом не резервируя соответствующие строковые значения.
Системные символы доступны как свойства функции Symbol , например Symbol.iterator .
Мы можем создавать и свои символы, использовать их в объектах. Записывать их как свойства Symbol , разумеется, нельзя. Если нужен глобально доступный символ, то используется Symbol.for(имя) .
Do'stlaringiz bilan baham: |