Могу ли я установить поле частного класса, используя переменную в качестве идентификатора? Как? - PullRequest
1 голос
/ 09 октября 2019

Node.js 12 поддерживает поля закрытого класса, обозначенные #"из коробки", без флагов и транспилеров.

Например, это работает с Node.js 12:

class Foo {
  #bar = 1;

  constructor({ bar }) {
    this.#bar = bar;
  }

  get bar() {
    return this.#bar;
  }
}

const foo = new Foo({ bar: 2 });

console.log(foo.bar); // 2

Допустим, я хочу создать свой экземпляр Foo не с 1 свойством, а с 20 - мне пришлось бы дублировать оператор присваивания в конструкторе и функции-получателе 20 раз, что составляет много шаблонного кода.

Если бы я не использовал частные поля, а обычные поля класса, этого было бы несложно избежать:

class Foo {
  bar = 1;

  constructor(properties) {
    Object.entries(properties).forEach(([name, value]) => (this[name] = value));
  }

  get bar() {
    return this.bar;
  }
}

const foo = new Foo({ bar: 2 });

console.log(foo.bar); // 2

Однако с частнымполя класса, это не работает:

class Foo {
  #bar = 1;

  constructor(properties) {
    Object.entries(properties).forEach(
      ([name, value]) => (this[`#${name}`] = value)
    );
  }

  get bar() {
    return this.#bar;
  }
}

const foo = new Foo({ bar: 2 });

console.log(foo.bar); // 1 :-(

Я также попытался присвоить значение полю частного класса в конструкторе, используя Reflect.set , но безрезультатно:

class Foo {
  #bar = 1;

  constructor(properties) {
    Object.entries(properties).forEach(([name, value]) =>
      Reflect.set(this, `#${name}`, value)
    );
  }

  get bar() {
    return this.#bar;
  }
}

const foo = new Foo({ bar: 2 });

console.log(foo.bar); // 1 :-(

Могу ли я установить поле частного класса, используя переменную в качестве идентификатора? Если да, то как?

1 Ответ

3 голосов
/ 09 октября 2019

Нет, это не представляется возможным. Из предложения FAQ :

Почему этот ['# x'] не получает доступ к закрытому полю с именем #x, если это делает #. X?

  1. Это усложнит семантику доступа к свойству.

  2. Динамический доступ к приватным полям противоречит понятию «приватный». Например, это касается:

class Dict extends null {
  #data = something_secret;
  add(key, value) {
    this[key] = value;
  }
  get(key) {
    return this[key];
  }
}
(new Dict).get('#data'); // returns something_secret

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

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

Вы даже не можете ссылаться на приватное поле, если оно явно не определено в теле класса ( не функция класса, но непосредственно внутри тела класса):

class Foo {
  // error is thrown because #abc must be defined in this section
  doSomething() {
    return this.#abc;
  }
}

Тем не менее, ничто не мешает вам создать частное свойство, которое является объектом со всеми этими свойствами объекта:

class Foo {
  #privates = {};

  constructor(properties) {
    Object.entries(properties).forEach(
      ([name, value]) => (this.#privates[name] = value)
    );
  }

  get privates() {
    return this.#privates;
  }
}

const foo = new Foo({ bar: 2 });

console.log(foo.privates.bar);
...