Как стать автором
Обновить

Комментарии 43

Пользуюсь lockahead в node10, так как начиная с этой версии было доступны без флага гармонии.


Приватным и свойствами объектов использую с 12 ноды, только в серверной коде

Когда уже сделают нормальную работу с юникодом в регулярках?
А что с юникодом не так? Уже давно работает. Добавляем в выражение флаг u и готово.
Например, вот выражение для получения заглавных букв, используя юникод:

/\p{Lu}/gu

или

/\p{Uppercase}/gu
Ну например:
"Я знаю, что Ваня хороший парень".search(/\bВаня\b/gu ); // выводит -1
"I know that John is a nice guy".search(/\bJohn\b/gu); // выводит 12

А для замены пресловутого "\w", приходится использовать конструкции вида:
const notALetterRegEx = /[^A-Za-zªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶ-ͷͺ-ͽΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԣԱ-Ֆՙա-ևא-תװ-ײء-يٮ-ٯٱ-ۓەۥ-ۦۮ-ۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴ-ߵߺऄ-हऽॐक़-ॡॱ-ॲॻ-ॿঅ-ঌএ-ঐও-নপ-রলশ-হঽৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽૐૠ-ૡଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽଡ଼-ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கங-சஜஞ-டண-தந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-ళవ-హఽౘ-ౙౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠ-ೡഅ-ഌഎ-ഐഒ-നപ-ഹഽൠ-ൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะา-ำเ-ๆກ-ຂຄງ-ຈຊຍດ-ທນ-ຟມ-ຣລວສ-ຫອ-ະາ-ຳຽເ-ໄໆໜ-ໝༀཀ-ཇཉ-ཬྈ-ྋက-ဪဿၐ-ၕၚ-ၝၡၥ-ၦၮ-ၰၵ-ႁႎႠ-Ⴥა-ჺჼᄀ-ᅙᅟ-ᆢᆨ-ᇹሀ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙶᚁ-ᚚᚠ-ᛪᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᤀ-ᤜᥐ-ᥭᥰ-ᥴᦀ-ᦩᧁ-ᧇᨀ-ᨖᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᰀ-ᰣᱍ-ᱏᱚ-ᱽᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₔℂℇℊ-ℓℕℙ-ℝℤΩℨK-ℭℯ-ℼ-ℿⅅ-ⅉⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-Ɐⱱ-ⱽⲀ-ⳤⴀ-ⴥⴰ-ⵥⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆷㇰ-ㇿ㐀-䶵一-鿃ꀀ-ꒌꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙟꙢ-ꙮꙿ-ꚗꜗ-ꜟꜢ-ꞈꞋ-ꞌꟻ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꤊ-ꤥꤰ-ꥆꨀ-ꨨꩀ-ꩂꩄ-ꩋ가-힣豈-鶴侮-頻並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ]|[\ud840-\ud868][\udc00-\udfff]|\ud800[\udc00-\udc0b\udc0d-\udc26\udc28-\udc3a\udc3c-\udc3d\udc3f-\udc4d\udc50-\udc5d\udc80-\udcfa\ude80-\ude9c\udea0-\uded0\udf00-\udf1e\udf30-\udf40\udf42-\udf49\udf80-\udf9d\udfa0-\udfc3\udfc8-\udfcf]|\ud801[\udc00-\udc9d]|\ud802[\udc00-\udc05\udc08\udc0a-\udc35\udc37-\udc38\udc3c\udc3f\udd00-\udd15\udd20-\udd39\ude00\ude10-\ude13\ude15-\ude17\ude19-\ude33]|\ud808[\udc00-\udf6e]|\ud835[\udc00-\udc54\udc56-\udc9c\udc9e-\udc9f\udca2\udca5-\udca6\udca9-\udcac\udcae-\udcb9\udcbb\udcbd-\udcc3\udcc5-\udd05\udd07-\udd0a\udd0d-\udd14\udd16-\udd1c\udd1e-\udd39\udd3b-\udd3e\udd40-\udd44\udd46\udd4a-\udd50\udd52-\udea5\udea8-\udec0\udec2-\udeda\udedc-\udefa\udefc-\udf14\udf16-\udf34\udf36-\udf4e\udf50-\udf6e\udf70-\udf88\udf8a-\udfa8\udfaa-\udfc2\udfc4-\udfcb]|\ud869[\udc00-\uded6]|\ud87e[\udc00-\ude1d]/ug;

Возможно у меня какое-то неправильное представление о полноценной поддержке Юникод, но я всегда думал что классы символов, вроде "\b", или "\w" должны отрабатывать одинаково для всех языков, или должны иметься Юникодовые аналоги.
Может я просто чего-то не знаю? Буду только рад, если мне укажут на ошибку.
В вашем первом примере можно сделать вот так:
regexr.com/4jj6t
"Я знаю, что Ваня хороший парень".search(/Ваня/gu)

А чтобы найти любую «букву» не обязательно перечислять все символы, достаточно указать просто параметр \p{Letter}, например:
regexr.com/4jj7c
/\p{Letter}+/gu


Я не могу подсказать как работать с \b \w, сам не разбираюсь, но возможно примеры на вот этом сайте вам помогут понять как это делать: www.regular-expressions.info/unicode.html

В вашем первом примере можно сделать вот так:
regexr.com/4jj6t
"Я знаю, что Ваня хороший парень".search(/Ваня/gu)


Ну вы же понимаете, что вопрос вовсе не в том, какими способами можно распарсить предложение из примера выше, а в том, что класс "\b", означающий границу слова, не работает, если в тексте присутствуют не латинские символы.
А чтобы найти любую «букву» не обязательно перечислять все символы, достаточно указать просто параметр \p{Letter}

К сожалению, пока только в Хроме и его производных. Так что пока рано отказываться от старых подходов. По крайней мере на фронтенде. На крайний случай есть библиотека XRegExp, если в проекте много работы с регулярными выражениями и не латинским текстом. Но ради пары регулярок, я её обычно не тащу.
Но в целом согласен. По крайней мере, в этом направлении есть определённый прогресс. И это хорошо.
Я не могу подсказать как работать с \b \w, сам не разбираюсь, но возможно примеры на вот этом сайте вам помогут понять как это делать: www.regular-expressions.info/unicode.html

Вы упускаете суть проблемы. Разумеется, существуют альтернативные способы определения границы слова, различной степени сложности и изощрённости, которые можно применить для юникода. И для прочих классов тоже можно подобрать альтернативу, где-то краткую и изящную на основе всяких \p{L}, где-то сложную и громоздкую, но в то же время рабочую, что уже не плохо. Но проблема не в этом.
Извиняюсь за тавтологию, но в данном случае, проблема в том, что вообще существует проблема, которой не должно быть. Ведь мы говорим о нормальной поддержке юникода, а не о хоть какой-нибудь. Классы символов, такие как \b, \w, \W и т.д., должны просто работать. В том числе с юникодом. Добавляя флаг u, я хочу от него именно такого поведения. Ведь это не только интуитивно и удобно, но и чисто практически, позволило бы использовать многие готовые регулярки, которые уже работают для латиницы. Кроме того, в других реализациях регулярных выражений, все эти классы: \b, \w, и т.д. — прекрасно работают с юникодом. Например, в C# они работают. В Qt они работают. Ну и конечно же, в Perl они работают:
Character classes in regular expressions match based on the character properties specified in the Unicode properties database.
\w can be used to match a Japanese ideograph, for instance;

Так что, ждать такого поведения вполне естественно. Ведь это и есть нормальная работа с юникодом. Почему в JS это не реализовано, для меня загадка.
От синтаксиса приватных переменных все еще коробит. Почему решетка? Ведь есть нормальная запись «private». Интересно, чем было вызван такой синтаксис? Возможно под капотом используют Symbol, а решетка, как указатель. Но как по мне — это какой-то костыль.
Читал где-то про такую позицию, что
class Super {
    ...
    equals (toCompare) {
        return this.field === toCompare.field
    }
}


JS не имеет типизации и toCompare может быть чем угодно => либо такой вот костыль (с решеткой), либо каждый раз движку проверять, что toCompare является того же типа и тогда уже проверять приватное поле, иначе — проверять публичное поле, что как бы уже не очень, ибо два разных поведения у одного написания.

Хотя меня все равно корежит от этой решеточки.

Скорее это желание лучше минифицировать и обфусцировать)

А почему бы не использовать наконец для чего-то решётку? В древности с её помощью можно было при определении объекта назначить один и тот же дочерний объект нескольким его свойствам. Эту штуку объявили устаревшей, с тех пор праздно болталась… То же самое касается собаки: ни CoffeeScript'овский сахар для this, ни декораторы в стандарт так и не перекочевали.

Впрочем, сама возможность умышленного сокрытия свойств, с целью не дать возможность пользователям библиотеки брать на себя ответственность за возможную поломку внутреннего состояния классов — спорная и пагубная практика. Ведь если припрёт, всё равно найдут способ это ограничение обойти — например, форкнуть библиотеку, и кому от этого хорошо? В других ООП-языках, когда идея инкапсуляции разбилась о суровую реальность, пришлось пост-фактум изобретать доступ к приватным свойствам через рефлексию. Странно, что JS в 2k19-м опять наступает на те же грабли.
По поводу собаки (@). Надеюсь что в будущем декораторы будут стандартом. В Typescript декораторы удобно использовать.
В других ООП-языках, когда идея инкапсуляции разбилась о суровую реальность

Это когда и где она разбилась?


пришлось пост-фактум изобретать доступ к приватным свойствам через рефлексию

Рефлексия не для доступа к приватным полям нужна. К слову, она может этого доступа и не предоставлять в принципе.

Это когда и где она разбилась?
Да ещё примерно после появления C++, когда попёрли реальные проекты на нём и стало ясно, что инкапсуляция может мешать. По этой причине в Python она не заложена вообще. В Java инкапсуляция есть, но почти с первой же версии (1.1) рефлексия появилась.
Рефлексия не для доступа к приватным полям нужна
Многие вещи используются не только для того, для чего изначально придуманы. Мало того: вещи, для которых предназначена рефлексия (сериализация и отладка), как раз и являются частными случаями, когда доступ к приватным полям таки нужен.
К слову, она может этого доступа и не предоставлять в принципе.
Может, но тогда она и непригодна в полной мере для своих задач. А где из языков с инкапсуляцией такое есть, к слову? В Java/C# могут быть ограничены права доступа, но с полными правами рефлексия полноценная. В PHP вроде вообще ограничений нет.

Еще можно отпатчить код, скормить его eval и обойтись без форка. Но логика почему необходимо именно такая строгая инкапсуляция, по моему, очень простая.


Если мы говорим про другие ООП языки, то видимо подразумеваем статически типизируемые, и где инкапсуляцию проверяет компилятор. В таком случае, нет ничего нелогичного в том, что можно отрефлексировать скрытые сущности во время выполнения, тут пользователь должен отдавать себе отчет куда он лезет. Однако для JS, где нет этапа компиляции и где мета-программирование самая обычная практика, возможность какого-либо взаимодействия со скрытыми сущностями во время выполнения, будет низводить все эти нововведения до конвенциональной инкапсуляции по типу: символ подчеркивания перед названием свойства или до объявления свойств через Symbol. Таким образом происходит потеря всякого смысла такой реализации.


На счет спорности практики ограничения ответственности я соглашусь. Но спорность уже как минимум субъективизирует свойство пагубности, с которым я не соглашусь. Чтобы не патчить код в рантайме или во время сборки, как вы заметили, придется делать форк. Что может иметь свои плоды для разработчиков библиотек. И что точно будет являться более безопасным вариантом для пользователей библиотек. В этом нет ничего плохого.

Лицензия не всегда позволяет сделать форк. В мире JS редко, но встречаются проприетарные библиотеки. Да и с LGPL, по идее, могут возникнуть проблемы, если сломать в форке совместимость с апстримом.

Я хотел показать, почему необходима именно такая реализация. И бессмысленность любой другой реализации как мне кажется вполне весомый аргумент. Тут уже скорее переходим к вопросу, нужна ли вообще инкапсуляция в JS. И с этим все очень просто: сейчас как правило для скрытия того, что действительно должно быть скрыто, используются Map или WeakMap, предложение к стандарту предлагает заменит это поведение на простую синтаксическую конструкцию, ну и плюс это поможет облегчить дебаг, а может и еще что-то. То есть все озвученные вами проблемы существуют и сейчас, и они никуда не денутся, однако при этом упростится участь разработчика, которому не придется городить лишнюю логику для реализации инкапсуляции. Короче этот стандарт нужно считать синтаксическим сахаром к реализации инкапсуляции через WeakMap.

Зачем такие извращения, если можно просто создать переменную в области видимости класса, к которой больше никто не имеет доступа? Например, завернув его в модуль, или, по старинке, в IIFE?

Таким образом можно только статические переменные объявить. Для переменных, которые необходимо соотносить именно с инстансом класса, приходится извращаться.

Классические конструкторы объектов (функции, которые напихивают свойства/методы объекта в свой this) лишены и этого недостатка. Можно объявлять переменные внутри конструктора: они будут доступны в методах и при этом уникальны для каждого объекта. Так что проблема, выходит, в ES6-ном сахаре для классов.

Именно. Правда классы значительно улучшают читаемость, дают наследование, простые акцессоры и прочие нищтяки, отказываеться от них уже прям какое-то ретроградство, как по мне. Но в целом да, новые предложения порождают новые проблемы, новые проблемы — новые предложения и т. д., обычно это принято называть прогрессом.

Ну цимес-то в том, что классика даёт куда больше возможностей. Полноценная функция — на то и полноценная функция. Например, можно в зависимости от входных данных присваивать в качестве метода две разные функции, чтобы не заводить в объекте лишнее свойство, в зависимости от которого выбирается вариант метода при каждом его вызове. Можно даже формировать одним конструктором объекты с разной структурой. Всю эту гибкость class-сахар не даст никогда. Затея, КМК, сугубо для программистов, переучивающихся с других языков с привычной непрототипной реализацией ООП. Прототипное ООП мощнее, но и освоить его сложнее, и выстрелить себе в ногу проще.

Прямое обращение к памяти компьютера и регистрам процессора тоже дает очень большое количество возможностей, и иногда без этого действительно не обойтись, хотя обычно это не нужно. Функции первого порядка в JS тоже открывают удивительные возможности, и благодаря им можно обходиться вообще без каких-либо других структур, но зачем?


По поводу классики: JS всегда сохраняет обратную совместимость, и любые классически решения, как и хаки, остаются доступными. Существование альтернатив, хоть и не таких гибких, но тем не менее решающих и упрощающих ряд задач, на мой взгляд это не плохо. И именно упрощения и строгости в структуре, хотят разработчики, голосующие за этот стандарт.


Касательно снижения планки сложности перехода с другого языка, возможно этот вопрос и поднимался (не следил за обсуждениями). Но как я уже и говорил выше, это решение скорее является сахаром к той практике, которая сложилась с WeakMap уже сейчас. Ничего принципиально нового этот синтаксис не вносит. И под капотом, судя по всему, это будет реализовываться именно так, как это уже делают.


Когда я только в первый раз Вам отвечал, у меня было неоднозначное отношение к этому предложению. Но чем больше писал, тем больше проникся пониманием зачем вообще нужно это нововведение и почему именно в таком исполнении.

JS всегда сохраняет обратную совместимость
Отнюдь. Такую базовую возможность, как вызов произвольных функций оператором new, конечно, вряд ли тронут — но с учётом того, как бурно в последние годы стал эволюционировать JS, я уже ничему не удивлюсь.
И именно упрощения и строгости в структуре
Ради строгости первым делом надо типизацию вводить. Ибо её реально не хватает и заменить толком нечем, в отличие от. Базовые типы можно хаками обеспечивать, как в Asm.JS, но не более. В результате наблюдается борьба прикрученных сбоку решений в виде TypeScript, Flow, PropTypes и ещё мелюзги.
Полностью согласен. Есть интересный случай из практики: на соседнем проекте был криво реализован oauth. Мы взяли какую-то стандартную нодовскую библиотеку для этих целей и пытались использовать, но потом выяснилось, что под наш случай она не подходит. И, хвала небесам, все, что было необходимо сделать, чтобы библиотека заработала — вызвать недокументированную приватную функцию с кастомными параметрами. Это не потребовало от нас форкать библиотеку, городить костыли для доступа к данным,… Просто сделали вызов функции и оставили комментарий с тремя восклицательными знаками почему здесь вызывается эта функция. И это позволило нам дальше участвовать в хакатоне, не тратя время понапрасну.

Ну и еще к слову о приватности: никогда не понимал как тестировать приватные методы. Приватный метод вполне может содержать нетривиальную логику и его надо обязательно протестировать. А городить костыли в виде пубичных методов, которые существуют единственно для того, чтобы вызвать приватный — уже какое-то убожество.

В принципе, возможность создать метод с подчеркивание и обозначить таким образом, что он приватный или дописав перед ним jsdoc-нотацию private мне всегда нравилась. При необходимости такие методы можно вызвать из консоли, их легко протестировать, легко отлаживать код, вызывая при необходимости такие методы прямо в дебаггере. Ну а то, что кто-то упрямо использует то, что ему сказали не использовать — ну сорян, сам мудак)
Приватный метод вполне может содержать нетривиальную логику и его надо обязательно протестировать
В Rust для решения этой проблемы тесты объявляются прямо в тестируемом модуле.
Я присутствовал на докладе комиссии TC39 в Берлине этим летом. Задал именно этот вопрос. Ответ был — потому что TypeScript набрал очень большую популярность и уже использует keyword «private». Как по мне, это очень странное решение, но Microsoft играет довольно большую роль в развитии JS, видимо им приходится договариваться.
НЛО прилетело и опубликовало эту надпись здесь

Причин этому синтаксису несколько:


  1. Это всё-таки синтаксис Hard Private соответственно задача закрыть доступ из вне всем и именно в рантайме.
  2. Обеспечение обратной совместимости с точки зрения комитета — не сломать имеющийся код изменением синтаксиса.
  3. Обеспечение обратной совместимости с точки зрения разработчиков — действительно закрыть доступ к полям, используемым для внутренней реализации классов и не предназначенных для внешнего использования.
  4. Упрощение реализации синтаксиса в движках в т.ч. в целях избежать ухудшение производительности.

Почему не использовать зарезервированное в ES ключевое слово private, которое уже применено в TypeScript:


  • Относительно TypeScript ключевое слово private предназначено непосредственно для разработчиков, которые читают и/или пишут конкретный код. Разработчики, которые используют библиотеку в своих проектах с огромной вероятностью не полезут в исходники библиотеки.
  • Так же это ключевое слово относительно TypeScript не влияет на рантайм т.к. при компиляции просто напросто вырезается. Соответственно как бы вы не именовали переменную она будет доступна окружению в рантайме. Следовательно ни чего не мешает использовать "приватную" по "соглашению" переменную игнорируя "соглашение", что в свою очередь довольно часто встречается в ES сообществе/экосистеме.
  • Пример такого использования: изменение поведения кода от наличия переменной или случай использования приватного метода, когда публичный метод и приватный метод выполняют на первый взгляд одно и тоже (однако публичный может так же иметь сайд эффекты).

Рассмотрим с точки зрения упрощения реализации синтаксиса и сохранения производительности:


  • Если бы мы вводили именно зарезервированное ключевое слово private для Hard Private, в реализациях движков пришлось бы любое обращение к любой переменной проверять на тип т.е. является ли данная переменная в данном объекте приватной или же публичной.
  • Как движки должны воспринимать случай, когда в родительском классе переменная является приватной, а в производном публичной — как воспринимать эту переменную при её использовании в каком скоупе и т.д.
  • Так же не забываем, что наименование переменной может быть откровенно говоря любого примитивного типа.
  • Опять таки относительно Hard Private (полного сокрытия) любая переменная объекта может быть получена подбором через синтаксис object[key], что в случае Hard Private не допустимо.

Это всё в свою очередь явно повлияло бы на производительность. Соответственно проще ввести какой-то дополнительный синтаксис, введение типа по примеру Symbol здесь не подходит в виду последнего пункта.


Какой это должен быть синтаксис? Первое, что приходит на ум это какой-то символ префикс т.к. данный подход по соглашению уже много где используют и это де-факто стандарт. Соглашение может отличаться от команды к команде, но ключевое здесь именно наличие какого-либо префикса.


Причём в сравнении с тем же ключевым словом соглашение по префиксу позволяет судить об области видимости переменной не возвращаясь к месту её объявления. Именно для этого данный подход и был придуман и используется совместно с такими ключевыми словами.


И так какой это должен быть символ-префикс, чтобы при этом не нарушить работу имеющегося кода и не забываем нам нужно избежать доступа через object[key]? (в object.field часть после точки заведомо интерпретируется движками как примитив string и эквивалентно object["field"])


И вот тут появляется символ #, который по стандарту dot notation является не верным и считается ошибкой (invalid) т.е. движки не будут считать часть после точки строкой это обеспечение обратной совместимости со стороны комитета. Таким образом object.#field это не object['#field'] и не object['field'] и не object[#field] т.к. #field не примитив. В реализации движков в данном случае заменяется выброс ошибки на обработку специфичного синтаксиса без проверок примитивного типа ключа (наименования переменной) т.к. это не требуется.


Разработчики библиотек могут получить пользу от Hard Private т.к. в случае если они решат изменить внутреннюю реализацию класса, изменив/заменив/убрав переменные внутренней реализации при этом оставив не изменной публичную часть (API), это будит действительно патч или минорное изменение.


Однако сейчас, когда приватные переменные (переменные внутренней реализации) это просто соглашение, которое часто игнорирует и используется в прямую производными библиотеками и кодом, данный патч/минорное обновление может вылиться и выливается в полноценное мажорное с нарушением обратной совместимости.


И всё из-за нарочного публичного использования заведомо не рассчитанных на это переменных.


Таким образом object.#field это во первых полностью скрытая в рантайме приватная переменная + соглашение по именованию, что позволяет судить о природе переменной в любой точке кода, где это используется, а так же должно восприниматься как совершенно отдельная/скрытая область.


К слову в том же TypeScript при компиляции приватных полей могли бы их помещать в WeakMap по принципу того, как babel компилирует синтаксис #field тем самым делая их на самом деле приватными. Однако в данном случае вызвалась бы коллизия с определением видимости переменной (что использовать и в каком месте — прямое обращение к object.field или к WeakMap).


И ещё замечу, что да # считается синтаксисом common comment в разных языка, НО не в ES (Здесь это именно //) так, что относительно данного языка это не нарушение.


Так же добавлю, что проблем с отладкой приватных переменных особо не должно быть т.к. тот же DevTools уже умеет как минимум отображать их и позволять изменить. А относительно методов можно и скостылить — выгрузить в temp переменную и вызвать через apply.

Спасибо за развернутый ответ. (плюсануть пока не могу, не дорос).
Это всё-таки синтаксис Hard Private соответственно задача закрыть доступ из вне всем и именно в рантайме.

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


Типичный пример героического преодолевания собственноручно созданных трудностей.

Вы докопались до терминологии задав произвольные интепретации так, чтобы Ваше возражение имело хоть какой-то смысл. "Из вне" — это значит за пределами класса, и когда мы говорим про инкапсуляцию в ООП, это очевидным образом подразумевается. Ваши характеристики "настоящий" или "ненастоящий" не имеют никакой фактической основы, а являются предметом риторики.


Это предложение по большей части надо расценивать как синтаксический сахар к реализации инкапсуляции через WeakMap.

Вы докопались до терминологии задав произвольные интепретации так, чтобы Ваше возражение имело хоть какой-то смысл. "

Есть вполне стандартная интерпретация, которая идет от стандартной реализации инкапсуляции в имеющихся ООП-языках. Эта реализация предполагает, что доступ к приватному полю есть только из контекста самого объекта. Никаких викмапов и прочей чуши для этого не надо — опять же, есть вполне стандартные реализации, проверенные десятилетиями.


Вместо этого в стандарт вместо инкапсуляции добавили кривой костыль, который потянул за собой другие кривые костыли. Вот и весь сказ.


Это предложение по большей части надо расценивать как синтаксический сахар к реализации инкапсуляции через WeakMap.

Нету никакой "реализации инкапсуляции через weakmap", это вообще НЕ инкапсуляция (т.к. переменная не скрыта), если только вы не придумаете свое собственное определение инкапсуляции, противоречащее общепринятому в ООП.


Это кривой костыль, антипаттерн, за использование которого следует отрывать руки. Вот для этого кривого костыля сделали столь же кривой сахар.

Есть вполне стандартная интерпретация, которая идет от стандартной реализации инкапсуляции в имеющихся ООП-языках. Эта реализация предполагает, что доступ к приватному полю есть только из контекста самого объекта. Никаких викмапов и прочей чуши для этого не надо — опять же, есть вполне стандартные реализации, проверенные десятилетиями.

Из того, что оказалось под рукой:
C++
#include <iostream>

class MyClass {
private:
    int member = 0;
public:
    int getMember() const {
        return member;
    }
    void setMemberOfOther(MyClass& other, int value){
        other.member = value;
    }
};

int main(int argc, char *argv[])
{
    MyClass a;
    MyClass b;

    a.setMemberOfOther(b,10);
    b.setMemberOfOther(a,20);

    std::cout << "a.member = " << a.getMember() << ", b.member = " << b.getMember() << std::endl;

    return 0;
}


C#
using System;

namespace Incaps
{
    class MyClass {
        private int member = 0;

        public int Member {
            get{ return member; }
        }

        public void SetMemberOfOther(MyClass other, int value){
            other.member = value;
        }

    }

    class MainClass
    {
        public static void Main(string[] args)
        {
            var a = new MyClass();
            var b = new MyClass();
            a.SetMemberOfOther(b,10);
            b.SetMemberOfOther(a,20);
            Console.WriteLine("a.Member = " + a.Member + ", b.Member = " + b.Member);
        }
    }
}


Не подскажете, в каких же имеющихся ООП-языках, присутствует «стандартная» реализация инкапсуляции, которую вы описываете?
Кривой костыль кривого костыля

Это предельный уровень аргументов, который Вы готовы поддерживать?


доступ к приватному полю есть только из контекста самого объекта

Во-первых, из контекста класса. В Java, C# и других языках, обычно это именно так и работает.


Во-вторых, строго говоря инкапсуляция и скрытие это разные термины, а однозначное и общепринятое определение инкапсуляции в ООП — это Ваша фантазия, причем с содержанием ошибки.


И следуя за Вашим ходом мысли: рефлексия, дружественные функции, динамическая смена типа и прочие механизмы позволяющие обойти ограничение на доступ к приватным данным в таких языках как C++, Java, C#, являются кривыми костылями, или реализация инкапсуляции в этих языках является кривым костылем, так как имеет больше количество способов ее обхода. В предлагаемом стандарте JS, замечу, озвученные способы обхода невозможны, как и любые другие, кроме переписывания кода (с этим можно извращаться и в рантайме), думаю от того Myateznik и назвал ее Hard Private.

Совершенно верно, только конкретно про название Hard Private это даже не я, а сам комитет так называет.

Раз уж вы стали цепляться за всё и вся начнём.


Нету никакой "реализации инкапсуляции через weakmap", это вообще НЕ инкапсуляция (т.к. переменная не скрыта)

Ну для начала в данном случае WeakMap единственный на один контекст, при этом не видимый для рантайм и юзается исключительно движком в целях реализации синтаксиса (рантайм не имеет прямого доступа к данному WeakMap), если это не "полное" скрытие, то видимо вы сами запутались.


О ваших рассуждений по поводу имеющихся ООП-языков и т.д. и т.п. не забывайте, что ES отличается от них во первых тем, что он мультипарадигменный язык и поддерживает не только ООП, но ещё и обобщённое, функциональное, императивное, аспектно-ориентированное, событийно-ориентированное, прототипное программирование соответственно уже будет иметь своё отличие в реализации.


Далее не забывайте про главное отличие от других ООП языков — прототипное наследование он сильно отличает ES от многих имеющихся ООП-языков и требует своих подходов в реализации.


Потом что же это такое «стандартная» реализация инкапсуляции и какой это стандарт и действует ли он во всех языках без исключений и не изменен ли он со временем?


ES это отдельный язык, у которого свой путь и принимаемые решения зависят на уже принятых ранее. Причём при всём при этом ES сохраняет обратную совместимость, чего не сказать про тот же Python (переход со 2 версии на 3 был довольно долгим и болезненным)


Никаких викмапов и прочей чуши для этого не надо

Уверены? И вы прям знаете точно во что превращает компилятор синтаксис приватных полей? И это прям точно не похоже на те же WeakMap? Вот серьёзно.


Типичный пример героического преодолевания собственноручно созданных трудностей.

Относительно вас могу так же сказать, что вы типичный пример разработчика, который пытается привнести поведение/инструменты привычного вам языка программирования в другой, что не так плохо, однако типичность заключается в отсутствии оценки применимости и возможности появления данных "инструментов" в конкретном языке.


Вы просто проигнорировали все отличия ES от того же C# или C++ и сказали, что должно быть 1 в 1. Более того ваши представления отличаются от действительности и выше вам на это уже казали.


С тем чтобы закрыть нет никаких трудностей

Приведите пример на ES, в котором будет очень легко реализовать закрытую переменную класса (причём переменная не static, а для каждого инстанса своя), но на синтаксисе ES6-ES10 с использованием синтаксического сахара классов. Главное эта переменная не должна быть доступна кому угодно кроме инстанса/инстансов класса.


И не забудьте оценить применимость вашего подхода при большем числе классов, а так же читаемость получившегося кода.


Лично я спокойно уже использую синтаксис приватных полей и методов в ES, мне действительно нужно защитить от прямого доступа из вне какой-нибудь массив. Т.к. я хочу во первых ограничить методы, вносящие правки, у меня есть обязательные сайд эффекты на эти действия. Вот допустим я делаю очередь воспроизведения медиа контента.


Символ # воспринимаю не более чем принятое языком соглашение по именованию приватных полей. Точно так же как бы использовал _ в других языках (в т.ч. в виду ограничений). Какая разница, что за символ главное своё назначение выполняет — в коде сразу видно приватное поле, в рантайме оно так же приватное (в отличии от _ и для меня этого достаточно).


То, что язык жёстко ограничивает выбор данного префикса — не плохо и не хорошо, тот же Go вообще жёстко ограничивает возможное число реализаций задачи, Python тоже приносит свои ограничения и ничего все пользуются.


В конце концов для каждого языка найдётся свой перечень задач, которые он решает хорошо — язык это только инструмент.

Блин, а почему не сделали подчеркивание то — ведь де факто его и использовали для обозначения private данных

Потому что тогда уже существующий код в какой-то момент начнёт работать иначе, чем работал для этого и, скорее всего, что-то сломается.

Обозначение private через решетку?
Означает ли это, что хеш-объект для хранения цветов в формате CSS станет нерабочим?

Другими словами, вызов colorHash["#dedede"] станет нерабочим?

Если да, то ждите поломок — хеши цветов используются, хотя и не так часто.

Нет. Подобные обращения останутся рабочими. Синтаксис предполагает обращение только через точку (this.#private), что в текущем стандарте является синтаксической ошибкой.

спасибо
Но при применении такого шаблона выбранными окажутся все слова в строке (MangoJuice, VanillaShake, GrapeJuice). Дело в том, что, по мнению системы, ни одно слово здесь не завершается Juice.

Отличное объяснение в стиле "мы только что объясняли, как должно работать, но почему-то не работает" и ещё более достойный фикс. Дело тут в том, что под регулярное выражение /a-zA-Z/ подходит и "Grap"+"eJuice", и "Gra"+"peJuice",… Решить эту проблему можно наложить дополнительные ограничения на контекст, например добавить "^|\s"в начало и ",|$" в конец

Зарегистрируйтесь на Хабре, чтобы оставить комментарий