Новшества JavaScript: итоги Google I/O 2019. Часть 1

Автор оригинала: Uday Hiwarale
  • Перевод
Материал, первую часть перевода которого мы сегодня публикуем, посвящён новым стандартным возможностям JavaScript, о которых шла речь на конференции Google I/O 2019. В частности, здесь мы поговорим о регулярных выражениях, о полях классов, о работе со строками.



Ретроспективные проверки в регулярных выражениях


Регулярные выражения (Regular Expression, сокращённо — RegEx или RegExp) — это мощная технология обработки строк, которая реализована во множестве языков программирования. Регулярные выражения оказываются очень кстати в тех случаях, когда нужно, например, выполнять поиск фрагментов строк по сложным шаблонам. До недавнего времени в JavaScript-реализации регулярных выражений имелось всё кроме ретроспективных проверок (lookbehind).

Для того чтобы разобраться с тем, что такое ретроспективная проверка, поговорим сначала об опережающих проверках (lookahead), которые уже поддерживаются в JavaScript.

Вторая часть

▍Опережающая проверка


Синтаксис опережающих проверок в регулярных выражениях позволяет выполнять поиск фрагментов строк, когда известно, что правее их находятся другие фрагменты. Например, при работе со строкой MangoJuice, VanillaShake, GrapeJuice можно воспользоваться синтаксисом положительной опережающей проверки для нахождения слов, сразу после которых идёт слово Juice. В нашем случае это — слова Mango и Grape.

Существует два вида опережающих проверок. Это — положительные опережающие проверки (positive lookahead) и отрицательные опережающие проверки (negative lookahead).

Положительная опережающая проверка


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

/[a-zA-Z]+(?=Juice)/

Этот шаблон позволяет выбирать слова, состоящие из строчных или прописных букв, после которых есть слово Juice. Не стоит путать структуры, описывающие опережающие и ретроспективные проверки, с группами (capture group). Хотя условия этих проверок и записываются в круглых скобках, система не выполняет их захвата. Давайте рассмотрим пример положительной опережающей проверки.

const testString = "MangoJuice, VanillaShake, GrapeJuice";
const testRegExp = /[a-zA-Z]+(?=Juice)/g;
const matches = testString.match( testRegExp );
console.log( matches ); // ["Mango", "Grape"]

Отрицательная опережающая проверка


Если рассмотреть, используя вышеприведённую строку, механизм действия отрицательных опережающих проверок, то окажется, что они позволяют находить слова, правее которых нет слова Juice. Синтаксис отрицательных опережающих проверок похож на синтаксис положительных проверок. Однако в нём имеется одна особенность, которая заключается в том, что символ = (равно) меняется на символ ! (восклицательный знак). Вот как это выглядит:

/[a-zA-Z]+(?!Juice)/

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

/(Mango|Vanilla|Grape)(?!Juice)/

Использование этого шаблона позволит выбрать слова Mango, или Vanilla, или Grape, после которых нет слова Juice. Вот пример:

const testString = "MangoJuice, VanillaShake, GrapeJuice";
const testRegExp = /(Mango|Vanilla|Grape)(?!Juice)/g;
const matches = testString.match( testRegExp );
console.log( matches ); // ["Vanilla"]

▍Ретроспективная проверка


По аналогии с синтаксисом опережающих проверок, синтаксис ретроспективных проверок позволяет выбирать последовательности символов только в том случае, если левее этих последовательностей находится некий заданный шаблон. Например, при обработке строки FrozenBananas, DriedApples, FrozenFish мы можем воспользоваться положительной ретроспективной проверкой для того, чтобы найти слова, левее которых есть слово Frozen. В нашем случае этому условию соответствуют слова Bananas и Fish.

Существуют, как и в случае с опережающими проверками, положительные ретроспективные проверки (positive lookbehind) и отрицательные ретроспективные проверки (negative или negating lookbehind).

Положительная ретроспективная проверка


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

/(?<=Frozen)[a-zA-Z]+/

Здесь используется символ <, которого не было при описании опережающих проверок. Кроме того, условие в регулярном выражении расположено не справа от интересующего нас шаблона, а слева. Используя вышеописанный шаблон можно выбрать все слова, начинающиеся с Frozen. Рассмотрим пример:

const testString = "FrozenBananas, DriedApples, FrozenFish";
const testRegExp = /(?<=Frozen)[a-zA-Z]+/g;
const matches = testString.match( testRegExp );
console.log( matches ); // ["Bananas", "Fish"]

Отрицательная ретроспективная проверка


Механизм отрицательных ретроспективных проверок позволяет искать в строках шаблоны, левее которых нет заданного шаблона. Например, если нужно выбрать в строке FrozenBananas, DriedApples, FrozenFish слова, которые не начинаются с Frozen, можно попытаться использовать такое регулярное выражение:

/(?<!Frozen)[a-zA-Z]+/

Но, так как использование этой конструкции приведёт к выбору всех слов из строки, так как ни одно из них не начинается с Frozen, регулярное выражение нужно уточнить:

/(?<!Frozen)(Bananas|Apples|Fish)/

Вот пример:

const testString = "FrozenBananas, DriedApples, FrozenFish";
const testRegExp = /(?<!Frozen)(Bananas|Apples|Fish)/g;
const matches = testString.match( testRegExp );
console.log( matches ); // ["Apples"]

→ Поддержка


В этом и в других подобных разделах будут приводиться сведения об этапе согласования описываемых возможностей JS в техническом комитете 39 (Technical Committee 39, TC39), который отвечает в ECMA International за поддержку спецификаций ECMAScript. В таких разделах будут приведены и данные о версиях Chrome и Node.js (а иногда и о версии Firefox), начиная с которых можно пользоваться соответствующими возможностями.


Поля классов


Поле класса — это новая синтаксическая конструкция, используемая для определения свойств экземпляров класса (объектов) за пределами конструктора класса. Существуют два типа полей классов: публичные поля (public class fields) и приватные поля (private class fields).

▍Публичные поля классов


До недавнего времени свойства объектов нужно было определять внутри конструктора класса. Эти свойства были публичными (общедоступными). Это означает, что к ним можно было обращаться, работая с экземпляром класса (объектом). Вот пример объявления общедоступного свойства:

class Dog {
    constructor() {
        this.name = 'Tommy';
    }
}

Когда нужно было создать класс, который расширял бы некий родительский класс, необходимо было вызывать super() в конструкторе дочернего класса. Делать это нужно было до того, как к дочернему классу можно было бы добавлять его собственные свойства. Вот как это выглядит:

class Animal {}
class Dog extends Animal {
    constructor() {
        super(); // вызываем super перед использованием `this` в конструкторе
        this.sound = 'Woof! Woof!';
    }
    makeSound() {
        console.log( this.sound );
    }
}
// создаём экземпляр класса
const tommy = new Dog();
tommy.makeSound(); // Woof! Woof!

Благодаря появлению синтаксиса публичных полей класса можно описывать поля класса за пределами конструктора. Система при этом выполнит неявный вызов super().

class Animal {}
class Dog extends Animal {
    sound = 'Woof! Woof!'; // публичное поле класса
    makeSound() {
        console.log( this.sound );
    }
}
// создаём экземпляр класса
const tommy = new Dog();
tommy.makeSound(); // Woof! Woof!

При неявном вызове super() ему передаются все аргументы, предоставленные пользователем при создании экземпляра класса (это — стандартное поведение JavaScript, тут нет ничего особенного, связанного с приватными полями классов). Если конструктор родительского класса нуждается в аргументах, подготовленных особенным образом, нужно вызвать super() самостоятельно. Взглянем на результаты работы неявного вызова конструктора родительского класса при создании экземпляра дочернего класса.

class Animal {
    constructor( ...args ) {
        console.log( 'Animal args:', args );
    }
}
class Dog extends Animal {
    sound = 'Woof! Woof!'; // публичное поле класса
makeSound() {
        console.log( this.sound );
    }
}
// создаём экземпляр класса
const tommy = new Dog( 'Tommy', 'Loves', 'Toys!' );
tommy.makeSound(); // Animal args: [ 'Tommy', 'Loves', 'Toys!' ]

▍Приватные поля классов


Как известно, в JavaScript нет модификаторов доступа к полям классов наподобие public, private или protected. Все свойства объектов по умолчанию являются публичными. Это означает, что доступ к ним ничем не ограничен. Ближе всего к тому, чтобы сделать некое свойство объекта подобным приватному свойству, можно подойти, используя тип данных Symbol. Это позволяет скрывать свойства объектов от внешнего мира. Возможно, вы пользовались именами свойств с префиксом _ (знак подчёркивания) для того чтобы указать на то, что соответствующие свойства нужно считать предназначенными лишь использования внутри объекта. Однако это — лишь нечто вроде уведомления для тех, кто будет пользоваться объектом. Это не решает проблему реального ограничения доступа к свойствам.

Благодаря механизму приватных полей классов можно сделать так, что свойства класса будут доступны лишь внутри этого класса. Это приводит к тому, что к ним нельзя обратиться извне и работая с экземпляром класса (объектом). Возьмём предыдущий пример и попробуем обратиться извне к свойству класса, при объявлении которого использовался префикс _.

class Dog {
    _sound = 'Woof! Woof!'; // это свойство должно считаться приватным
    
    makeSound() {
        console.log( this._sound );
    }
}
// создаём экземпляр класса
const tommy = new Dog();
console.log( tommy._sound ); // Woof! Woof!

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

SyntaxError: Undefined private field

Вот пример:

class Dog {
    #sound = 'Woof! Woof!'; // это - приватное свойство
    makeSound() {
        console.log( this.#sound );
    }
}
// создаём экземпляр класса
const tommy = new Dog();
tommy.makeSound() // Woof! Woof!
//console.log( tommy.#sound ); // SyntaxError

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

Объявлять приватные (и публичные) поля можно и не записывая в них некие значения:

class Dog {
    #name;
    constructor( name ) {
        this.#name = name;
    }
    showName() {
        console.log( this.#name );
    }
}
// создаём экземпляр класса
const tommy = new Dog( 'Tommy' );
tommy.showName(); // Tommy

→ Поддержка


  • TC39: Stage 3
  • Chrome: 74+
  • Node: 12+

Метод строк .matchAll()


В прототипе типа данных String имеется метод .match(), который возвращает массив фрагментов строки, соответствующих условию, заданному регулярным выражением. Вот пример использования этого метода:

const colors = "#EEE, #CCC, #FAFAFA, #F00, #000";
const matchColorRegExp = /([A-Z0-9]+)/g;
console.log( colors.match( matchColorRegExp ) );
// Вывод:
["EEE", "CCC", "FAFAFA", "F00", "000"]

При использовании этого метода, однако, не даётся дополнительных сведений (вроде индексов) о найденных фрагментах строки. Если убрать флаг g из регулярного выражения, передаваемого методу .match() — он вернёт массив, в котором будут содержаться дополнительные сведения о результатах поиска. Правда, при таком подходе найден будет лишь первый фрагмент строки, соответствующий регулярному выражению.

const colors = "#EEE, #CCC, #FAFAFA, #F00, #000";
const matchColorRegExp = /#([A-Z0-9]+)/;
console.log( colors.match( matchColorRegExp ) );
// Вывод: (для удобства просмотра тут представлен сокращённый вариант вывода)
["#EEE", "EEE", index: 0, input: "<colors>"]

Для того чтобы получить нечто подобное, но уже для нескольких фрагментов строки, придётся пользоваться методом регулярных выражений .exec(). Конструкции, которые для этого нужны, сложнее, чем та, в которой для получения подобных результатов использовался бы вызов единственного метода строки. В частности, здесь нам понадобится цикл while, который будет выполняться до тех пор, пока .exec() не вернёт null. Пользуясь этим подходом, учитывайте то, что .exec() не возвращает итератор.

const colors = "#EEE, #CCC, #FAFAFA, #F00, #000";
const matchColorRegExp = /#([A-Z0-9]+)/g;
// в строгом режиме будет выдано сообщение об ошибке,
// Uncaught ReferenceError: match is not defined
while( match = matchColorRegExp.exec( colors ) ) {
  console.log( match );
}
// Вывод: (для удобства просмотра тут представлен сокращённый вариант вывода)
["#EEE", "EEE", index: 0, input: "<colors>"]
["#CCC", "CCC", index: 6, input: "<colors>"]
["#FAFAFA", "FAFAFA", index: 12, input: "<colors>"]
["#F00", "F00", index: 21, input: input: "<colors>"]
["#000", "000", index: 27, input: input: "<colors>"]

Для того чтобы решать подобные задачи, теперь мы можем пользоваться методом строк .matchAll(), который возвращает итератор. Каждый вызов метода .next() этого итератора приводит к возврату очередного элемента из результатов поиска. В результате вышеприведённый пример можно переписать так:

const colors = "#EEE, #CCC, #FAFAFA, #F00, #000";
const matchColorRegExp = /#([A-Z0-9]+)/g;
console.log( ...colors.matchAll( matchColorRegExp ) );
// Вывод: (для удобства просмотра тут представлен сокращённый вариант вывода)
["#EEE", "EEE", index: 0, input: "<colors>"]
["#CCC", "CCC", index: 6, input: "<colors>"]
["#FAFAFA", "FAFAFA", index: 12, input: "<colors>"]
["#F00", "F00", index: 21, input: input: "<colors>"]
["#000", "000", index: 27, input: input: "<colors>"]

→ Поддержка


  • TC39: stage 4
  • Chrome: 73+
  • Node: 12+
  • Firefox: 67+

Именованные группы в регулярных выражениях


Концепция групп в JavaScript-реализации механизмов регулярных выражений немного отличается от реализации аналогичной концепции в других языках. А именно, когда, пользуясь JavaScript, RegEx-шаблон помещают в круглые скобки (за исключением тех случаев, когда круглые скобки используются для оформления ретроспективных или опережающих проверок), шаблон превращается в группу.

Захваченные группой фрагменты строки найдут отражение в результатах применения регулярного выражения.

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

["#EEE", "EEE", index: 0, input: "<colors>"]

Если в регулярном выражении имеется несколько групп, то они попадут в результаты обработки строки в порядке их описания в регулярном выражении. Рассмотрим пример:

const str = "My name is John Doe.";
const matchRegExp = /My name is ([a-z]+) ([a-z]+)/i;
const result = str.match( matchRegExp );console.log( result );
// если константа result равна null - возникнет ошибка
console.log( { firstName: result[1], lastName: result[2] } );
// Вывод:
["My name is John Doe", "John", "Doe", index: 0, input: "My name is John Doe.", groups: undefined]
{firstName: "John", lastName: "Doe"}

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

Использование именованных групп позволяет сохранять то, что захватывают группы, внутри объекта groups, имена свойств которого соответствуют именам, назначенным группам.

const str = "My name is John Doe.";
const matchRegExp = /My name is (?<firstName>[a-z]+) (?<lastName>[a-z]+)/i;
const result = str.match( matchRegExp );
console.log( result );
console.log( result.groups );
// Вывод:
["My name is John Doe", "John", "Doe", index: 0, input: "My name is John Doe.", groups: {firstName: "John", lastName: "Doe"}]
{firstName: "John", lastName: "Doe"}

Надо отметить, что именованные группы нормально работают и вместе с методом .matchAll().

→ Поддержка


  • TC39: Stage 4
  • Chrome: 64+
  • Node: 10+

Продолжение следует…

Уважаемые читатели! Пользовались ли вы уже какими-нибудь из описанных здесь новшеств JavaScript?

RUVDS.com
1 180,18
RUVDS – хостинг VDS/VPS серверов
Поделиться публикацией

Похожие публикации

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

    0

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


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

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

        /\p{Lu}/gu

        или

        /\p{Uppercase}/gu
          0
          Ну например:
          "Я знаю, что Ваня хороший парень".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" должны отрабатывать одинаково для всех языков, или должны иметься Юникодовые аналоги.
          Может я просто чего-то не знаю? Буду только рад, если мне укажут на ошибку.
            0
            В вашем первом примере можно сделать вот так:
            regexr.com/4jj6t
            "Я знаю, что Ваня хороший парень".search(/Ваня/gu)

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


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

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


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

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

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

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

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

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


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

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

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

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


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


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

                      0

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

                        0

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

                          0

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

                            0

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

                              0

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

                                0

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

                                  0

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

                                    0

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


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


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


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

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

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

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

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


                          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.

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

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


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

                                0

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


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

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

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


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


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

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


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

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

                                    Из того, что оказалось под рукой:
                                    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);
                                            }
                                        }
                                    }
                                    


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

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


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

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


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


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

                                        +1

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

                                        0

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


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

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


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


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


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


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


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

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


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

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


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


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

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


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


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


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


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


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

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

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

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

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

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

                                    +1

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

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

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

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

                                    Самое читаемое