Подтвердить что ты не робот

ES6 Итерация над методами класса

Учитывая этот класс; как бы я перебирал методы, которые он включает?

class Animal {
    constructor(type){
        this.animalType = type;
    }
    getAnimalType(){
        console.log('this.animalType: ', this.animalType );
    }
}

let cat = window.cat = new Animal('cat')

То, что я пробовал, не имеет успеха:

for (var each in Object.getPrototypeOf(cat) ){
    console.log(each);
}
4b9b3361

Ответ 1

Вы можете использовать Object.getOwnPropertyNames прототип:

Object.getOwnPropertyNames( Animal.prototype )
// [ 'constructor', 'getAnimalType' ]

Ответ 2

я знаю, я знаю, но эй...

const isGetter = ( x, name ) => ( Object.getOwnPropertyDescriptor( x, name ) || {} ).get
const isFunction = ( x, name ) => typeof x[ name ] === "function";
const deepFunctions = x => 
  x && x !== Object.prototype && 
  Object.getOwnPropertyNames( x )
    .filter( name => isGetter( x, name ) || isFunction( x, name ) )
    .concat( deepFunctions( Object.getPrototypeOf( x ) ) || [] );
const distinctDeepFunctions = x => Array.from( new Set( deepFunctions( x ) ) );
const userFunctions = x => distinctDeepFunctions( x ).filter( name => name !== "constructor" && !~name.indexOf( "__" ) );


// example usage

class YourObject {   
   hello() { return "uk"; }
   goodbye() { return "eu"; }
}

class MyObject extends YourObject {
   hello() { return "ie"; }
   get when() { return "soon"; } 
}

const obj = new MyObject();
console.log( userFunctions( obj ) ); // [ "hello", "when", "goodbye" ]

Ответ 3

Поскольку методы класса ES6 неперечислимы, у вас нет другого варианта, кроме как использовать Object.getOwnPropertyNames() для получения массива всех его свойств.

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

Проверьте следующий фрагмент:

Object.getOwnPropertyNames(Animal.prototype).forEach((value) => {
    console.log(value);
})

Ответ 4

проверьте эту скрипту

https://jsfiddle.net/ponmudi/tqmya6ok/1/

class Animal {
    constructor(type){
        this.animalType = type;
    }
    getAnimalType(){
        console.log('this.animalType: ', this.animalType );
    }
}

let cat = new Animal('cat');

//by instance
document.getElementById('1').innerHTML = Object.getOwnPropertyNames(cat);

//by getting prototype from instance
document.getElementById('2').innerHTML = Object.getOwnPropertyNames(Object.getPrototypeOf(cat));

//by prototype
document.getElementById('3').innerHTML = Object.getOwnPropertyNames(Animal.prototype);

Ответ 5

Если вам также нужны методы суперкласса, вы можете называть Object.getPrototypeOf() несколько раз, пока не найдете их все. Вероятно, вам захочется остановиться, когда вы перейдете к Object.prototype, потому что методы там фундаментальны, и вы обычно не хотите трогать их каким-либо кодом, который использует отражение.

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

export function listMethodNames (object, downToClass = Object)
{
    // based on code by Muhammad Umer, https://stackoverflow.com/a/31055217/441899
    let props = [];

    for (let obj = object; obj !== null && obj !== downToClass.prototype; obj = Object.getPrototypeOf(obj))
    {
        props = props.concat(Object.getOwnPropertyNames(obj));
    }

    return props.sort().filter((e, i, arr) => e != arr[i+1] && typeof object[e] == 'function');
}

Как и исправление ошибки в исходном коде (который не копировал объект в другую переменную для цикла, поэтому к моменту, когда он был использован для фильтрации в обратной линии, он больше недействителен), это дает необязательный аргумент, чтобы остановить итерацию в настраиваемом классе. По умолчанию он будет Object (поэтому исключаются методы Object; если вы хотите включить их, вы можете использовать класс, который не отображается в цепочке наследования... возможно, создание класса маркера, например class IncludeObjectMethods{} может иметь смысл). Я также изменил цикл do на более четкий цикл for и переписал функцию фильтра function ... старого стиля в функцию со стрелкой ES6, чтобы сделать код более компактным.

Ответ 6

Для тех, кто использует машинописный текст, который интересуется такими вопросами, вы можете сделать много вещей простым способом, используя метаданные-отражение api. Например, вы можете добавлять метаданные к своим классам с помощью декораторов и получать информацию о методах классов, их свойствах и их типах. Typcript и его типы позволяют делать подобные вещи на скомпилированные языки, такие как java, С# и их апостроф.

Взгляните на эти ссылки для получения дополнительной информации:

https://www.typescriptlang.org/docs/handbook/decorators.html

https://www.npmjs.com/search?q=reflect-metadata

Ответ 7

Попробуйте использовать этот один лайнер, если вам нужны только функции (например, замена на _.функции)

function getInstanceMethodNames (obj) {
    return Object
        .getOwnPropertyNames (Object.getPrototypeOf (obj))
        .filter(name => (name !== 'constructor' && typeof obj[name] === 'function'));
}

Ответ 8

Это расширенная версия ответа, предложенного здесь fooobar.com/questions/211424/...

По умолчанию я добавляю параметр deep, deep = Infinity, чтобы извлечь все функции, включая родительские. deep = 1 для извлечения прямых методов данного класса.

getAllMethods = function (obj, deep = Infinity) {
    let props = []

    while (
      (obj = Object.getPrototypeOf(obj)) && // walk-up the prototype chain
      Object.getPrototypeOf(obj) && // not the the Object prototype methods (hasOwnProperty, etc...)
      deep !== 0
    ) {
      const l = Object.getOwnPropertyNames(obj)
        .concat(Object.getOwnPropertySymbols(obj).map(s => s.toString()))
        .sort()
        .filter(
          (p, i, arr) =>
            typeof obj[p] === 'function' && // only the methods
            p !== 'constructor' && // not the constructor
            (i == 0 || p !== arr[i - 1]) && // not overriding in this prototype
            props.indexOf(p) === -1 // not overridden in a child
        )
      props = props.concat(l)
      deep--
    }

    return props
  }
  

class Foo {
  
  method01 (){
  }
  
  method02 (){
  }
  
  }
  
  
  class FooChield extends Foo {
  
  method01(){
  }
  
  method03(){
  }
  } 
  

  
  console.log('All methods', getAllMethods(new FooChield())) 
  
  console.log('Direct methods', getAllMethods(new FooChield(),1))

Ответ 9

Это немного сложнее, но получает методы из всей цепочки прототипов.

function getAllMethodNames (obj, depth = Infinity) {
    const methods = new Set()
    while (depth-- && obj) {
        for (const key of Reflect.ownKeys(obj)) {
            methods.add(key)
        }
        obj = Reflect.getPrototypeOf(obj)
    }
    return [...methods]
}