IT TIP

클래스의 함수 (메소드) 가져 오기

itqueen 2020. 12. 7. 21:24
반응형

클래스의 함수 (메소드) 가져 오기


이 질문에 이미 답변이 있습니다.

ES6 클래스의 속성과 기능을 동적으로 가져와야합니다. 이것이 가능할까요?

for ... in 루프를 사용하면 클래스 인스턴스의 속성 만 반복합니다.

class Foo {
  constructor() {
    this.bar = "hi";
  }
  someFunc() {
    console.log(this.bar);
  }
}
var foo = new Foo();
for (var idx in foo) {
  console.log(idx);
}

산출:

bar

이 함수는 모든 함수를 가져옵니다. 상속 여부, 열거 가능 여부. 모든 기능이 포함되어 있습니다.

function getAllFuncs(obj) {
    var props = [];

    do {
        props = props.concat(Object.getOwnPropertyNames(obj));
    } while (obj = Object.getPrototypeOf(obj));

    return props.sort().filter(function(e, i, arr) { 
       if (e!=arr[i+1] && typeof obj[e] == 'function') return true;
    });
}

테스트 수행

getAllFuncs([1,3]);

콘솔 출력 :

["constructor", "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "entries", "keys", "constructor", "toString", "toLocaleString", "valueOf", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "__defineGetter__", "__lookupGetter__", "__defineSetter__", "__lookupSetter__"]

노트

기호를 통해 정의 된 함수는 반환하지 않습니다.


클래스의 멤버는 열거 할 수 없습니다 . 이를 얻으려면 다음을 사용해야합니다 Object.getOwnPropertyNames.

var propertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf(foo));
// or
var propertyNames = Object.getOwnPropertyNames(Foo.prototype);

물론 이것은 상속 된 메서드를 얻지 못할 것입니다. 그들 모두를 줄 수있는 방법은 없습니다. 프로토 타입 체인을 탐색하고 각 프로토 타입의 속성을 개별적으로 가져와야합니다.


ES6는 코드를 좀 더 깔끔하게 만드는 Reflection을 추가합니다.

function getAllMethodNames(obj) {
  let methods = new Set();
  while (obj = Reflect.getPrototypeOf(obj)) {
    let keys = Reflect.ownKeys(obj)
    keys.forEach((k) => methods.add(k));
  }
  return methods;
}


/// a simple class hierarchy to test getAllMethodNames


// kind of like an abstract base class
class Shape {
  constructor() {}
  area() {
    throw new Error("can't define area for generic shape, use a subclass")
  }
}

// Square: a shape with a sideLength property, an area function and getSideLength function
class Square extends Shape {
  constructor(sideLength) {
    super();
    this.sideLength = sideLength;
  }
  area() {
    return this.sideLength * this.sideLength
  };
  getSideLength() {
    return this.sideLength
  };
}

// ColoredSquare: a square with a color
class ColoredSquare extends Square {
  constructor(sideLength, color) {
    super(sideLength);
    this.color = color;
  }
  getColor() {
    return this.color
  }
}


let temp = new ColoredSquare(2, "red");
let methods = getAllMethodNames(temp);
console.log([...methods]);


@MuhammadUmer 답변에는 몇 가지 문제가 있었기 때문에 (기호, 색인 i+1, Object방법 목록 등) 영감을 얻었습니다.

(ES6로 컴파일 된 경고 Typescript)

const getAllMethods = (obj) => {
    let props = []

    do {
        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)
    }
    while (
        (obj = Object.getPrototypeOf(obj)) &&   //walk-up the prototype chain
        Object.getPrototypeOf(obj)              //not the the Object prototype methods (hasOwnProperty, etc...)
    )

    return props
}

이 함수는 상속 된 것을 포함하여 클래스 인스턴스의 모든 메서드를 나열 하지만 생성자와 Object 프로토 타입의 메서드를 나열 합니다 .

테스트

함수는

[ 'asyncMethod',
  'echo',
  'generatorMethod',
  'ping',
  'pong',
  'anotherEcho' ]

TestClass(typescript) 인스턴스의 메서드 나열

class Echo  {
    echo(data: string): string {
        return data
    }
    anotherEcho(data: string): string {
        return `Echo ${data}`
    }
}


class TestClass extends Echo {

    ping(data: string): string {
        if (data === 'ping') {
            return 'pong'
        }
        throw new Error('"ping" was expected !')
    }

    pong(data: string): string {
        if (data === 'pong') {
            return 'ping'
        }
        throw new Error('"pong" was expected !')
    }

    //overridden echo
    echo(data: string): string {
        return 'blah'
    }

    async asyncMethod(): Promise<string> {
        return new Promise<string>((resolve: (value?: string) => void, reject: (reason?: any) => void) => {
            resolve('blah')
        })
    }

    * generatorMethod(): IterableIterator<string> {
        yield 'blah'
    }
}

클래스의 멤버를 열거 가능하게 만들려면 Symbol.iterator를 사용할 수 있습니다.

나는 (상속 된 것을 포함하여) 허용 된 모든 객체 메소드를 얻어야했다. 그래서 "Enumerable"클래스와 그로부터 상속받은 모든 기본 클래스를 만들었습니다.

class Enumerable {
  constructor() {

    // Add this for enumerate ES6 class-methods
    var obj = this;

    var getProps = function* (object) {
      if (object !== Object.prototype) {
        for (let name of Object.getOwnPropertyNames(object)) {
          let method = object[name];
          // Supposedly you'd like to skip constructor and private methods (start with _ )
          if (method instanceof Function && name !== 'constructor' && name[0] !== '_')
            yield name;
        }
        yield* getProps(Object.getPrototypeOf(object));
      }
    }

    this[Symbol.iterator] = function*() {
      yield* getProps(obj);
    }
    // --------------
  }
}

참고URL : https://stackoverflow.com/questions/31054910/get-functions-methods-of-a-class

반응형