Object.create() и собственные частные поля

#javascript

#javascript

Вопрос:

Когда я создаю экземпляр класса через Object.create(Example.prototype) , чтобы обойти его конструктор, больше невозможно работать с собственными частными полями:

 class Example {
  #myPrivateProp;

  setup() {
    this.#myPrivateProp = 1;
  }
}

const e1 = new Example();
const e2 = Object.create(Example.prototype);
console.log(e1.setup()); // works
console.log(e2.setup()); // fails with Uncaught TypeError: Cannot write private member #myPrivateProp to an object whose class did not declare it 

Есть ли способ заставить это работать, сохраняя неизменность отказа от вызова конструктора?

Для контекста вы можете увидеть эту проблему: https://github.com/mikro-orm/mikro-orm/issues/1226

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

1. При использовании собственных частных полей нет .

2. Именно поэтому частные поля — плохая идея: они нарушают отражение. Тот, кто хочет их использовать, должен знать об этом.

3. Для вашего контекста: лицо, определяющее частное поле, также отвечает за предоставление пары serialise методов / deserialise (или toJSON / fromJSON ). Вы можете попробовать создать его с помощью своего декоратора, но для этого потребуется вызвать конструктор. (Что на самом деле не должно быть проблемой, если конструктор написан правильно и только инициализирует экземпляр, не выполняя побочные эффекты).

Ответ №1:

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

У вас есть два варианта;

  1. Статическое приватное поле, принадлежащее Example классу, к которому можно обращаться и которым можно взаимно управлять любым экземпляром этого класса или даже объектами, созданными подобным Object.create(Example.prototype) образом .

такие как;

 class Example {
  static #SECRET = 0;
  constructor(){
  }

  addOne() {
    return   Example.#SECRET;
  }
}


i1 = new Example();
i2 = new Example();
console.log(i1.addOne()); // <- 1
console.log(i2.addOne()); // <- 2
i3 = Object.create(Example.prototype);
console.log(i3.addOne()); // <- 3
Example.#SECRET = 4;      // <- Uncaught SyntaxError: Private field '#SECRET' must be
                          //    declared in an enclosing class
 
  1. Поле частного экземпляра принадлежит экземпляру и может быть доступно и обрабатываться только этим экземпляром. Как это достигается, точно видно из вашего примера кода. Каждый отдельный экземпляр будет иметь свой собственный #myPrivateProp , что, если вы спросите меня, прекрасная вещь. Например, можно создать множество отдельных очередей, и их критически важные свойства не будут раскрыты.

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

1. » не частное поле, а поле частного экземпляра». — поле частного экземпляра — это просто особый вид частного поля.

2. » Поле частного экземпляра принадлежит экземпляру и может быть доступно и обрабатываться только этим экземпляром » — это неправда. К закрытому полю можно получить доступ с помощью любого кода внутри class , из статических методов, а также методов, которые были вызваны в других экземплярах. Вы имели в виду «можно получить доступ только через экземпляр»? Но это ничем не отличается от обычного свойства, зависящего от конкретного экземпляра.

3. Я действительно не понимаю, как это отвечает на вопрос о вызове setup() метода для объекта, созданного с помощью Object.create