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

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

Странно, почему нельзя придерживаться единого стиля наименования?
Приватное поле "#", статическое «static».

Ну либо уж дальше одним символом обозначать и static тоже, либо словом «private» приватное поле (что с моей тз лучше и читабельней).

Потому что приватные поля находятся в отдельном пространстве имён, в отличии от статических. Свойство foo и #foo — это два разных свойства, а не одно с двумя областями видимости.


Напомню, что любое свойство foo можно прочитать через квадратные скобки: obj['foo']. А вот с приватными свойствами такое не работает.


Мне вот больше интересно почему метод hasOwn попал в Object, а не в Reflect...

Речь была про обозначение — токен «private» vs "#".
Причем тут область видимости / пространство имен?

Предположим, сделано как вы предлагаете. Вот вы пишете: obj.foo. Как интерпретатор должен понять, вы к публичному свойству foo обратились или к приватному?

По внутреннему описателю свойства «foo» во внутренней объектной структуре.
Что было объявлено первым, то и есть, иначе кидается исключение.

Грубо говоря при парсинге исходника у свойства «foo» взводится флаг, что оно — приватное (или статическое и т.д.) и переопределить это нельзя. Область должна быть одна — в одном объекте (или цепочке объектов наследования) свойство с одинаковым именем, но разными областями видимости — это стрельба себе в ногу.

Тогда сломается прозрачность при наследовании.


class Foo { #name="foo"; printFoo() { console.log(this.#name); } }
class Bar extends Foo { #name="bar"; printBar() { console.log(this.#name); } }

const obj = new Bar();
obj.printFoo(); // foo
obj.printBar(); // bar

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


Кстати, вот ещё прикол:


class Foo { name = "foo"; }
class Bar extends Foo { #name = "bar"; }

const obj = new Bar();
console.log(obj.name); // foo

А как у вас смогут одновременно существовать унаследованное публичное и приватное свойство с одним именем?

При вызове метода из объекта, метод оперирует скопом данного объекта же?

Т.е. если private name в классе FOO, и метод printFoo в классе FOO, то при вызове его из отнаследованого класса, скоп будет FOO, а не BAR (перегрузки не было) => выдаст «foo».

А при вызове printBar мы обращаемся к объекту BAR, соответственно скоп будет его, и он выведет его private name => выдаст «bar».

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

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


При вызове метода из объекта, метод оперирует скопом данного объекта же?

А как тогда вот этот пример разрулить?


class Foo {
    #name = "foo";

    print1(obj) {
        console.log(obj.name);
    }

    print2(obj) {
        console.log(obj.#name);
    }
}

Как вы выразите отличие между методами print1 и print2?

Представьте, что базовый класс находится в библиотеке. С вашим подходом любое добавление свойства потенциально может оказаться ломающим изменением.
Каким образом? Если свойство в библиотеке объявлено как «private», то при любом наследовании от нее, оно и останется «private», что где ломается? Или вы имеете ввиду, что где-то вверху, при наследовании, кто-то объявил такое-же свойство с другим типом? Ну в таком случае сразу будет понятно где ошибка по эксепшену и это нормально. Ну и при наследовании от библиотек, да и в принципе при наследовании от того, что может меняться независимо, есть хороший тон — использовать префиксы перед переменными, чтобы избежать конфликтов. Потому как гораздо более печально будет, если перетрется значение переменной в верхнем классе и при этом вы не получите ни какого предупреждения.

Как вы выразите отличие между методами print1 и print2?
obj — это откуда? можно пополней пример?

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

Если, например, private name для объекта o, и вы попробуете сделать o.name = "..." => получите ошибку, так как оно — приватное, если попробуете отнаследовать класс от o, у которого это свойство будет другого типа (например было обычным, хотите чтобы стало приватным) => также получите ошибку. Т.е. для объекта не может быть свойства с одинаковым именем и разным типом на любом уровне наследования, включая сам объект — т.е. случай, где у объекта есть обычное свойство name и приватное свойство name физически невозможен, только один из вариантов.

Вобщем все тоже самое что в ООП для C++.
Каким образом?

Очень просто. Свойства в библиотеке вообще не было, а в новой версии появилось. В производном же классе оно было, и после обновления зависимости возник конфликт.


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

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


obj — это откуда? можно пополней пример?

Ну держите полнее:


class Foo {
    #name = "foo";
    print1(obj) { console.log(obj.name); }
    print2(obj) { console.log(obj.#name); }
}

const obj = new Foo();
obj.print1({ name: "bar" });
obj.print2(obj);

Вобщем все тоже самое что в ООП для C++.

Совсем не то же самое. На плюсах типы статические, что всё упрощает. И приватные члены из родительского класса полностью невидимы в дочернем.

Это вопрос производительности при обращении к полю. Если видим решетку, то остаётся проверить в правильном ли скоупе мы сейчас. С private надо каждый раз искать определение свойства и проверять, приватно ли оно.

Плюс, решеткой можно пользоваться и без синтаксиса полей класса. Просто написав в конструкторе this.#privateField = 42, вы уже получаете приватное поле.

Чем дальше, тем больше похоже на клинопись. Лет через десять будем на эмодзи писать.
С одной стороны повышает порог вхождения (я за), с другой - экономия на спичках.

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