Нужно ли в javascript думать о private свойствах и методах?
Третий день я сижу и читаю, но придти самостоятельно к ответу не смогу, но очень надеюсь что вы мне сможете помочь.
Впитав концепцию классов в других языках, мне очень сложно себя перестроить. На первый взгляд, как мне казалось, очень легкий и простой js, превратился для меня в болото, из которого я только выбравшись, попадаю снова. И для меня самое сложное было не контекст и прототипное наследование, а отсутствие классов и модификаторов доступа.
С первого дня я смерился с отсутствием private, но что-то тянуло меня разобраться и я с Вашей помощью выяснил, что private все же можно воссоздать, но и это меня тоже не успокоило. Сегодня я полез на githab и начал смотреть код известных фраймворков и не увидел там приватных свойств.
И этот факт подтолкнул меня задать этот вопрос, но прежде я немножечко расскажу, что я хочу услышать.
Бывает так, что новички, в языках с которыми я знаком, спрашивают вещи, которые я бы никогда не сделал и я всегда объясняю, что это противоречит тому-то или тому-то и говорю, как бы сделал я. Но иногда бывает так, что просто даю им ответ и что они там с этим делать будут, мне безразлично.
И теперь и я хочу спросить - нужно ли заморачиваться на private в js
или стоит принять за правило, что в js просто не нужны эти приваты?
Когда я спрашиваю "нужны ли приваты", то подразумеваю не какой-то частный случай, а спрашиваю "нужно ли, как под копирку, создавать все объекты с приватными свойствами и методами, как если бы я это делал в языках с классами?"
Или же private нужно и Вы сами применяете только в частных случаях?
В питоне вообще нет модификаторов доступа, и все поля доступны по прямому доступу. И ничего страшного в этом нет. В js такая же ситуация. Более того, все эти заморочки с private заставляют зачастую генерить кучу геттеров и сеттеров, которые будут нарушать инкапсуляцию. Так что заморачиваться не стоит, ведь даже в яве можно с помощью ухищрений добраться до приватных полей через рефлексию.
Решение может быть таким: обозначать какие-то внутренние переменные и методы с символа подчёркивания. Они по-прежнему будут публичными, но для разработчика это знак, что такое поле не понадобится при использовании твоей библиотеки. А методы и переменные, необходимые только для одного публичного метода какого-нибудь класса можно делать локальными, чтобы не плодить кучу полей.
А можно поинтересоваться, почему set-get нарушают инкапсуляцию?
На сколько я помню, все свойства должны быть private, а set-get созданы для того, чтобы управлять инкапсуляцией. То есть, в сеттер можно поставить условие, нужно ли менять значение, а геттер может отдать или нет любой объект-значение.
Инкапсуляция это всегда хорошо. Вопрос в том нужны ли вам приватные методы и свойства? Они хороши в контексте классов, что бы разграничить интерфейс и реализацию. В JS же объект является интерфейсом. То есть он не может иметь скрытого состояния. Точнее может но не в самом объекте, а в другом каком...
В Python-мире есть такая точка зрения по поводу отсутствия модификаторов досупа, которая выражается выражением "We're all consenting adults here" (все мы тут взрослые люди). То есть по мнению большинства поставить _ перед названием приватных методов достаточно что бы разработчики их не использовали. В JS даже это крайне не рекомендуется делать, так как у вас есть скоупы и все что нужно спрятать вы можете сокрыть там. Так же в ES6 появится WeakMap которые помогут хоть немного упростить разруливание скрытого состояния и уменьшит вероятность утечек памяти.
Если посмотреть на фреймворки, например AngularJS активно использует $$ перед именем приватного свойства или метода. Причем в добавох в jsdoc эти свойства отмечены как private и если указать соответствующие опции для минификаторов, то те переименуют эти свойства и тогда разработчику будет уже тяжело предсказать как оно будет называться в следующем релизе.
Хочу уточнить - не рекомендуется создавать приватные свойства и методы или не рекомендуется создавая псевдоприватные свойства,
начинать их с _подчеркивания?
@vasIvas: вы не можете создать приватные методы и свойства, следовательно вы можете только добавлять какие-то символы вроде _ к именам методов и свойств. Именно это и не рекомендуется. Сокрыть состояние или методы можно закрыв их в своей области видимости к которой имеет доступ только методы объекта.
Инкапсуляция это всегда хорошо. Вопрос в том нужны ли вам приватные методы и свойства? Они хороши в контексте классов, что бы разграничить интерфейс и реализацию. В JS же объект является интерфейсом. То есть он не может иметь скрытого состояния.
Сергей Протько: ещё вопрос - давая совет новичку в as3 о классах, я бы описал модель из первой вспомнившейся книги И.. Вот все что после И нужно разложить более детально, так как объяснив ему стандартную формулировку я бы не соврал и подал информацию в том виде, в котором новичок бы смог её переварить. Но есть и другая сторона, я лично редко использую стандартную модель, так как у меня есть кучи фабрик, которые работают с Assetmanager, у которого я и забираю по Enum константе или строковому значению, то что мне нужно.
Вот и мне у Вас хочется спросить - Вы сами пишите простыми объектами или у Вас есть реализации классов или фабрики, которые и объект и scope его создают и контролируют?
@vasIvas: scope контролировать у вас не выйдет. Я думаю вам стоит перестать загоняться и заниматься сравнением AS3 и JS. Это принципиально разные языки, смиритесь с этим. Если хотите еще мозг полапать - возьмите rust или haskell побаловаться.
Сергей Протько: я специально делаю упор на классы, только для того, чтобы подробно все разузнать. Вот если бы я начал изучать язык с классами, то я бы знал что нужно спрашивать и отвечающие бы меня понимали, а в js я не могу спросить то, о чем ещё не подозреваю. Я делал несколько попыток, но безуспешно и на этот раз я решил спрашивать так, как могу. И ещё настроен разобраться до конца, по этому я задам ещё несколько вопросов.
@vasIvas: как по мне делать упор на классы при изучения языка, где их нет... это как-то странно. Вы в итоге будете делать неверные выводы и не усвоите идею языка.
@vasIvas: Бога нет. Если что это книга. Остальное какой-то бред, мне даже сказать на него нечего.
Всем нравятся его книги, только вы у нас самый умный, но никак это не проявляется к сожалению. www.amazon.com/Nicholas-C.-Zakas/e/B001IGUTOC/ref=...
Да я не говорю что я самый умный и "евангелистом" он себя не из-за религии назвал... Тогда объясните мне, как можно назвать обсервер , медиатором, а mvp фасад + медиатор + модуль ?
@vasIvas: In the original book that coined the terms Observer and Mediator, Design Patterns, Elements of Reusable Object-Oriented Software it says that the Mediator pattern can be implemented by using the observer pattern.
@vasIvas: скажите честно, вы даже не прочитали ничего. Я вот начал лихорадочно искать там хоть что-то эдакое возмутительное... и как-то не нашел. А автор этой книги весьма уважаемый разработчик.
Сергей Протько: я всю прочел, но автор называет обсервер медиатором так, будто не существует шаблона медиатор. А его модель приложения, это чистой воды mvp, ult фасад это презентер, медиатор у него полуактивная модель, полу глобальный диспетчер. А если модуль управлял бы чем-то визуальным и его можно было бы назвать представлением, то все это вместе называлось бы mvp. Если изменить все названия на названия mvp, то статья бы не изменилась, а была бы соответствием статьи с wiki о mvp. @UbuRus: я согласен в том, что сравнивать их нельзя, это два разных патерна. И посмотрите у него код "медиатора", который реализует методы обсервера. Обсервер у него не композицией, а чистая реализация, как его можно медиатором называть?
@vasIvas: MVP это не шаблон проектирования а лишь идея разделения приложения на отдельные уровни/слои, используя шаблоны проектирования. Так что не "фасад это презентер" а "презентер у нас тут это фасад". Я не сильно внимательно читал эту книжку, просто пробежался по общим моментам, и мне показалось что там больше про MVA речь идет. И да, таки в книжке речь идет именно о медиаторе/посреднике, а не о обсервере. Не пойму откуда вы его там взяли.
1. "я всю прочел, но автор называет обсервер медиатором так, будто не существует шаблона медиатор." Из книги: "Пример: одна из возможных реализаций паттерна «медиатор»". Т.е. это лишь вариант реализации медиатора. И главный вопрос данный код инкапсулирует общение между модулями? Еще раз, медиатор и обсервер это партерны разного уровня.
2. "Обсервер у него не композицией, а чистая реализация, как его можно медиатором называть?" Код на JS правильного реализованного медиатора на основе обсервера в студию!
Вместо того чтобы сидеть и теоретизировать, лучше напишите свой форум на nodejs. Хотя нет, сначала напишите медиатор, с правильной композицией обсервера. На JS.
@UbuRus: там не написано что это mvp, но в mvp суть такова есть перезентер, берет на себя часть обязанностей у модели ( нужно ли сообщить это модели или нет ) делая тем самым модель полуактивной,
которая, тоже реализует диспетчера и от своей оставшейся части активности, рулит приложением. Но только у автора нет представления..
Но дело не в этом. Я удалил первый пост и извиняюсь перед Вами обоими, за грубость - извините!
В защиту хочу сказать, что если бы не она, то возможно я бы не понял того, что все это время скрывали от меня классы. До меня только сейчас дошла истина того, что означает "реализация интерфейса". В классах есть прелесть в том, что они разграничивают логику на отдельные классы и собирают все при помощи наследия, которое и закрывало мне суть. То есть я бы в одном классе никогда не увидел и реализацию диспетчера и реализацию собственного поведения. Для меня бы это было разбросанно по классам, но суть то, как я только сейчас понял в том, что в итоге бы я получил лист в котором все сведено в одно. И тут бы как раз и получилось, что медиатор РЕАЛИЗУЕТ диспетчера, а фасад это всего лишь api - public методы класса...
Сейчас я прав?
Да, фасад это api. Если перевести на язык Java, то один модуль в JS отлично ложится на класс в Java. В фасад выносятся все паблик методы. Филды в фасад не нужно выносить, лучше спрятать за методом, тогда будет проще рефакторить либо менять логику.
В JS отсутсвует прямой эквивалент интерфейсу в Java, но это из-за природы языка. Он тут не нужен. Вы легко можете подменить реализацию:
var module;
if (prod) {
module = require('/prod-module.js');
} else {
module = require('/dev-module.js');
}