Как перебирать свойства экземпляра класса ES6/2015

учитывая эти два класса

class Foo{
  f1;

  get f2(){
    return "a";
  }
}

class Bar extends Foo {
  b1;

  get b2(){
    return "a";
  }
}

let bar = new Bar();

Какой код доставит мне этот список свойств из экземпляра bar? ['f1', 'f2', 'b1', 'b2']

Вот пример Babel


Обновить

Это должно быть частью ответа @Marc C:

Используя декоратор, я могу легко превратить неперечислимое свойство в перечисляемое свойство:

class Bar extends Foo {

  @enumerable()  
  get b2(){
    return "a";
  }

}

Вот исходник декоратора:

function enumerable() {
  return function(target, key, descriptor) {
    if (descriptor) {
      descriptor.enumerable = true;
    }
  };
}

Вот пример Babel


person Sylvain    schedule 07.01.2016    source источник
comment
Честно говоря, это похоже на дубликат stackoverflow.com/questions/ 31054910/получить-функции-класса. Нет причин делать свойства перечисляемыми.   -  person loganfsmyth    schedule 08.01.2016
comment
babel: библиотека интернационализации Python с упором на веб-приложения. Если у вас есть вопросы о библиотеке JavaScript, используйте [babeljs].   -  person Felix Kling    schedule 08.01.2016


Ответы (2)


Это не допустимый синтаксис для объявления свойств в классе. Вместо этого объявите их в конструкторе.

class Foo {
  constructor() {
    this.f1 = undefined;
  }
}

Затем вы можете получить их с помощью Object.keys.

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

class Foo {
  f1 = 0;
  ...
}

Что касается доступа к геттерам, геттеры по умолчанию не являются перечисляемыми, и к ним нельзя получить доступ с помощью Object.keys или любого подобного механизма. Однако вы можете создавать перечисляемые геттеры, используя Object.defineProperty.

Object.defineProperty(bar, 'f2', {
  get() { 
    return "a"; 
  }
});

Если вы используете экспериментальные функции ES7, вы можете применить декоратор к методу класса и получить такое же поведение. См. это пример Babel.

class Foo {
  @enumerable()
  get b2() {
    return "a";
  }
}

function enumerable() {
  return function(target, key, descriptor) {
    if (descriptor) {
      descriptor.enumerable = true;
    }
  }
}
person Mike Cluck    schedule 07.01.2016
comment
1 — я использую эту экспериментальную функцию, которую поддерживает Babel (для f1 и b1). 2 - Object.keys() не понимает меня b2 и f2. - person Sylvain; 07.01.2016
comment
@Sylvain Babel может принять это, но если вы посмотрите на скомпилированный код, f1 и b1 не объявлены. Babel объявит их, если вы присвоите им такие значения, как f1 = 0. Что касается f2 и b2, геттеры не перечисляются по умолчанию. - person Mike Cluck; 07.01.2016
comment
хорошая точка зрения. 1 - я могу это исправить (и оставить вне конструктора), если я установлю для них значение undefined. 2 - Есть ли функция, которая даст мне список этих геттеров или они действительно скрыты? - person Sylvain; 07.01.2016
comment
@Sylvain Они действительно скрыты, когда написаны в этом формате. Используя Object.defineProperty, вы можете создать перечисляемый геттер, и он будет виден. - person Mike Cluck; 07.01.2016
comment
Проверьте мое обновление выше, если вы считаете, что это хорошая идея, добавьте его в свой ответ, и я приму его (я не осмелился обновить ваше редактирование вашего ответа) - person Sylvain; 08.01.2016
comment
@Sylvain Интересно, я не знал о декораторах ES7. Обновлен мой ответ, чтобы включить их. Спасибо за это. - person Mike Cluck; 08.01.2016
comment
Еще одна вещь, Object.keys(bar) не работает. Мне пришлось использовать for (let p in bar), чтобы получить все 4 свойства. Это тоже следует добавить к вашему ответу. - person Sylvain; 08.01.2016
comment
Вы можете легко получить все свойства, используя Object.getOwnPropertyNames, даже если они не являются перечисляемыми. Делать их перечисляемыми совершенно не связано с возможностью их перечисления, если вы не используете for...in. См. stackoverflow.com/questions/31054910/get-functions- первоклассный - person loganfsmyth; 08.01.2016
comment
Я также должен получить f1 и f2, которые унаследованы от Foo; Object.getOwnPropertyNames не вернет их. - person Sylvain; 08.01.2016
comment
Как говорится в ответе на вопрос, на который я ссылался, вам нужно пройти цепочку прототипов, потому что getOwnPropertyNames возвращает только own свойства. for...in проходит цепочку прототипов, вам тоже нужно это сделать. В данном конкретном случае свойства находятся на прямом прототипе Object.getOwnPropertyNames(Object.getPrototypeOf(a)) - person loganfsmyth; 08.01.2016
comment
Это, конечно, старый ответ, но, поскольку это выбранный ответ, я подумал, что добавлю, что есть предложение (которое, вероятно, пройдет), которое добавляет объявления полей класса github.com/tc39/proposal-class-fields и есть подключаемый модуль Babel для обработки этого синтаксиса babeljs.io/docs/en/babel-plugin-proposal-class-properties - person Knight Yoshi; 23.11.2018

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

function getAllPropertyNames(obj) {
  let names = [];
  do {
    names.push.apply(names, Object.getOwnPropertyNames(obj));
    obj = Object.getPrototypeOf(obj);
  } while(obj !== Object.prototype);
  return names.filter(name => name !== 'constructor');
}
person Felix Kling    schedule 08.01.2016