Pull to refresh

Comments 61

Мне одному кажется, что этот Symbol огромный костыль? Какой-то очень нетривиальный тип данных, имеющий странное название, при использовании которого есть много исключений из правил.
Нет. Читаю и думаю «Что за...» с фейспалмом за изготове.
Да нафик не нужны эти приватные члены в javascript. Используйте просто нотацию имён, с _ — private, без — всё остальное.
А вот динамически вычисляемые поля в json это круто. Интересно если результат вычисления null или undefined, то поле будет добавлено в объект?
Полагаю, поведение будет таким же, как и при
a[null] = 1; a[undefined] = 2;
.

А приватность нужна разработчикам библиотек. А то завяжется кто-то на приватное свойство — ему показалось так удобнее, затем этот костыль попадет в известные «фичи», его начнут рекомендовать и использовать. В итоге приватное свойство уже не приватное и его нельзя изменить.
Клиент всегда прав, и если много программистов начинают использовать приватное свойство в своих целях — значит создатель библиотеки ошибся в архитектуре и нужно было сделать это свойство публичным, или предусмотреть другой способ выполнени того действия, которого хотят таким образом добиться. Иначе люди будут менять исходный код (иногда и мне приходится) и всё равно добиваться нужного функционала. Если я подключаю библиотеку — я надеюсь, что она будет удовлетворять моим требованиям, и не надо ничего запрещать. Оповестил, что приватное, спасибо, действую на свой страх и риск.
UFO landed and left these words here
По существу с Вами согласен. Но в принципе думаю: пусть будет. Приватные члены, конечно не нужны, но какое-нибудь применение ему найдётся.
Это всё же не JSON.
В других языках этот тип тоже встречается.
Если мне не изменяет память, схожей (или даже такой же) семантикой обладают атомы в Prolog'е или символы в Ruby.
Насколько мне известно, символы в Ruby — один из вариантов представления строки и числа: при создании символа строка навсегда (пока работает интерпретатор) связывается с числом и :foo в разных модулях есть один и тот же символ.

Впрочем, такое поведение приводит к уязвимости типа DoS в определённых случаях и вроде бы «навсегда» уже не такое «навсегда».

Символы здесь можно сравнить с типом object в Python (если забыть, что это родитель всех (Python 3) или почти всех остальных классов): написав foo = object(), единственное, что вы можете сделать с foo полезного есть использование его в качестве гарантированно уникального объекта, который можно получить только через уже существующую ссылку. Удобно, если вы хотите что-то (де)сериализовывать и нуждаетесь в уникальном специальном значении типа True, False и None: свой класс здесь ещё не нужен, но другие примитивные типы использовать уже нельзя (они могут быть десериализованы из представления значения примитивного типа). Больше я нигде и низачем такое не использовал: в Python всё равно что-то скрыть можно, только написав это что-то на C/…
Нет, семантика скорее обратная. В Ruby гарантируется, что
:foo == :foo # => true
'foo'.to_sym == :foo # => true
a = :foo
b = :foo
a == b # => true

Это просто что-то вроде констант всеобщего назначения с хорошей производительностью сравнения (потому что внутри это числа).
И действительно…
Полезная штука на самом деле, если бы появилась в языке с самого начала, можно было бы обходиться без костылей типа __proto__ в объекте.
Без __proto__ можно было бы обойтись и без символов, если бы изначально были добавлены Object.(get|set)PrototypeOf. Если бы символы появились в языке с самого начала, это бы избавило от костылей типа toString и прочих методов Object.prototype, ломающих словари. А теперь — поздно пить боржоми =\
На самом деле это очень старая идея — в CLOS используется похожая схема для инкапсуляции.
Symbol это не костыль, а весьма мощный подход для создания примесей. Символы позволяют примешивать в объект методы и связанные с ними состояния, при этом не оголяя состояния. Если символов нет, в худшем случае придётся вести отдельную мапу, в которой будут храниться некоторые искуственные id для объектов и связанные с ними значения стейста примеси (и поддерживать актуальность мапы), в более лучшем варианте WeakMap, где вместо ключа уже выступает сам объект. Но символ решает эту задачу чище, позволяя хранить стейт прямо в объекте и при этом не засоряя никакие ключи (коллизий нет в принципе). Также символ автоматически решает задачу освобождения памяти — как только объект с примесью уничтожается, состояния примесей также уничтожаются, потому что они хранятся в объекте.

Символы (вместе с WeakMap-ами) позволят лучше организовать вещи, наподобие jQuery.data, разрешат некоторые ситуации с ивентами а также будут отличным подспорьем в FRP, помогая решить ситуации с текущей памятью. Символы решат много интересных задач в библиотечном коде. В коде приложения символы же можно использовать как простой enum, например. Уверен, найдутся и другие применения.

И да, в отличие от многих других фич нового стандарта (от которого я далеко не в восторге), Symbol не является сахаром. 80% остальных нововведений это либо сахар, либо вещи, которые уже давно прекрасно реализуются библиотеками.
мне кажется, или это то же самое, что и unique_id()?
ну почти, unique_id можно вывести.
Рискну сказать: может быть, пора уже признать, что Javascript был с самого начала спроектирован в спешке и для других целей, и в 21-ом веке может быть можно уже заменить его какой-нибудь более подходящей для современной разработки альтернативой, в которой не надо городить костыли?
По мне, так лучше бы оставили затею сделать из JS серьёзный интструмент и запилили бы что-то TypeScript/Dart-подобное, нативное на новой виртуальной машине.
UFO landed and left these words here
UFO landed and left these words here
Питон пока слабо поддерживается браузерами
UFO landed and left these words here
Ну здрасте!

    var role = Symbol();
    var user = {
        id: 1001,
        name: 'Administrator',
        [role]: 'admin'
    };

user.role; 
// -> undefined
user.role = 'User';

Что будет если так? У user два свойства role одно публичное, одно приватное? Если да, то это опять какое-то недо-ООП.
Да, у объека user будет два свойства:

    Object { id: 1001, name: 'Administrator', role: 'User', Symbol(): 'admin' }

А что именно здесь нелогично (ты ведь сам создаешь одно публичное и одно приватное свойство role), почему это подпадает под недо-ООП?
Это почва для огромного количества потенциальных ошибок. Кроме того, это семантически неверно. Такое не прокатит ни в PHP, ни в Java, например.
Это прокатит абсолютно в любом языке, где атрибуты можно брать по именам, взятым из переменной. Воспринимайте это так, как будто вы назвали атрибут a56d843e_dd66_11e4_be1e_50465d597777, записали эту строку в переменную и сказали, что будете обращаться исключительно через неё.
Здесь своя семантика. У вас не два свойства role, у вас одно role, а другое — объект Symbol по адресу 0xNNNNNNNN. Назвать его затем можно как угодно: название переменной к самому объекту гвоздями не прибито. То, что программист библиотеки выбрал совпадающие имена — это личная проблема программиста. Он раньше точно так же мог использовать role и _role. При некоторых условиях такое даже имеет смысл: в Python так обычно реализуют «ленивые» атрибуты классов, если их в проекте всего несколько.

Может вы хотите в публичном свойстве хранить объект RoleProxy с ограниченными возможностями, а в приватном — полноценный Role.
Еще хотел добавить, что понятие типа Symbol уже имеет свою семантику в языках программирования. Гомоиконные языки имеют тип symbol, а в JS это вводит только непонятную неразбериху. Увидел заголовок, подумал, что этот тип данных как-то будет связан со структурами данных именно самого языка и будет представлять собой именно эти структуры (как символы в Лиспе, например). Но вот уж чего точно не ожидал, так то что это тип для приватных свойст. Короче говоря, как-то это нелогично очень.
Да, зря они это дело назвали символом, поскольку это прямо противоположная вещь символам и атомам из других языков. Путаница будет дичайшая.
Возможно глупый вопрос, но почему нельзя в таком случае вместо ключа использовать просто Object(), зачем нужен особый тип?
Если попытаться использовать Object() в качестве ключа, он будет приведён к строке [object Object].
Обязательное приведение ключей словаря к строке — это какая-то детская болезнь для языков, из которой JS и PHP никак не вырастут.
Это ваше мнение, я с ним не согласен. Для словарей с объектами в качестве ключей есть Map и WeakMap.
Когда они будут поддерживаться большинством браузеров, тогда и можно будет сказать, что выросли. Пока что поддержка на мобильных устройствах оставляет надежды на будущее.
Они поддерживаются всеми актуальными браузерами, а для устаревших всегда есть полифилы.
Строго говоря, можно добиться этого поведения, реализовав интерфейс ArrayAccess у объекта и творить что-то вроде:
$m = new Map();
$obj = new Object();
$m[$obj] = "woo";


Но от невозможности работы с ключами отличными от целочисленного или строки во встроенных массивах это не избавит.
В PHP есть еще spl_object_hash(), но это все равно костыли.
Все остальные аспекты будут рассмотрены в последующих частях (я ведь это отметил в конце статьи). Вся информация будет поделена на логические части, в этой была затронута только тема символов как тип данных.
Ну Iterator protocol с символами связан только тем, что использует well-known символ Symbol.iterator. Множество другой логики ES6+ использует well-known символы — toStringTag, species и т. д.

Статья — да, поверхностная, но посмотрите на последний абзац — явно указано, что это только начало.
Подскажите, а в чем приватность метода, если я все же могу получить значение, используя symbol. Или я чего-то не понял?
Попадёт ли свойство, объявленное через symbol к ребёнку при наследовании?
Символы не приватные ключи, а уникальные. Их предназначение — предотвращение перекрытия свойств в пользовательском коде. Символы также можно получить через Object.getOwnPropertySymbols и Reflect.ownKeys. Свойство по ключу-символу наследуется точно так же, как и обычное свойство. Для приватных данных сейчас можно использовать WeakMap, хотя и они не являются полностью приватными (можно перехватить скрытые данные, обернув методы прототипа коллекции). Для хранения приватных данных, в ES7+ планируется добавить приватные поля — эта концепция, к сожалению, заменила более удачную, с моей точки зрения, концепцию абстрактных ссылок.
В статье этот концепт был подан как приватные свойства, но если сделать основной акцент на то, что это способ создавать уникальные свойства (как указано в комментарии выше), то мне уже не кажется это костылем, а, наоборот, вполне себе фича. Тем более, что есть даже метод Symbol.for(), который позволяет хранить символы глобально для «среды текущего выполнения». То есть их приватность — это все также соглашение, а не закон.

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

Какая свобода потенциально возможна: какие-то члены в виде символов, какие-то забиты в WeakMap, какие-то в виде обычных замыканий, какие-то в виде _ (немного приватные), какие-то в виде __ (чуть больше приватные), и тут еще будут модификаторы в будущих спецификациях (настоящие приватные). А еще говорят, что JS — это «детский язык». Да более мощного механизма приватных членов нигде нет :)
Автор, я умоляю тебя обратить внимание на одну важную часть: черновик ES6! =) Во всём посту и в комментариях ни слова о сей существенной детали, говорящей, что всё это пока не стандарт и может быть изменено.

Вы эпизодически говорите «спецификация ECMAScript». Но такой сущности нет. Есть только черновик спецификации ECMAScript.
Ничего уже не может быть изменено. Текущая версия — RC4 — финальная и именно она будет утверждаться ECMA в июне.
Спасибо за линк. Стоило это упомянуть в статье.

минусить вы в праве, но...
Официальный статус на момент написания — черновик. Где не прав?
Деталь существенная. Не хотел бы я жить в здании построенном на техническом черновике, а не утверждённом по всем протоколам чертежам. Где не прав?
Возможно твит правда, кто в ответе если нет? (я надуюсь, что это так, но рассчитывать на это в серьёзных приложениях стоит ли?.. Серьёзных = материальная ответственность)
Не хотел бы я жить в здании построенном на техническом черновике, а не утверждённом по всем протоколам чертежам.


Можно подумать, будто таких зданий не строят, пообщайтесь с инженерами-конструкторами :)
С несколько десятков многоэтажек стоит со статусом «самострой». А ещё людей сбивают машины, их убивают микроорганизмы. Наличие явление это одно, а желание (или нежелание) быть к нему причастным — другое)

Подумать можно всегда.., только WAT? при чём тут мои слова?) Это как «я не хотел бы быть сбитым машиной» и трактовка «можно подумать, будто людей не сбивают машины. Пообщайтесь с ДПС» =)
Как уже ответили выше, можно не переживать, что это черновик, так как все уже утверждено и войдёт в спецификацию. Последнюю версию (Release Candidate 4 от 3 апреля) можно найти — здесь.
Если вас связали боровы и везут в лес — тоже можно не переживать =)
Как написал выше, этими сведениями не стоило преминуть. Для ясности.
Кстати. А что произойдет, если объект с ключом типа Symbol прогнать через JSON.stringify? Он никак не отобразится при сериализации?
Да, будет проигнорирован
Я не видел, но когда посмотрел, испугался. Цитируя один мультфильм, скажу: «Мы впервые столкнулись с человеком, у которого совершенно нет личной жизни».
Не знаю его, но он жёсткий тип. Проделана колоссальная работа. И не только по es6.
Занятная ссылочка. Захожу, начинаю читать, само собой, снизу. Reflect. ES6 пример — копипаста моего из документации core-js, что позже скопировал в документацию babel. ES5 пример сломан, пишу issue — исправляют. Двигаюсь дальше, следующий пример — Proxy, тоже сломан. Пишу issue — автор проблемы не видит. Дальше читать уже боюсь.
Only those users with full accounts are able to leave comments. Log in, please.