获取类的函数(方法)

Jan*_*Jan 61 javascript oop ecmascript-6

我必须动态获取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);
}
Run Code Online (Sandbox Code Playgroud)

输出:

bar
Run Code Online (Sandbox Code Playgroud)

Fel*_*ing 43

类的成员不可枚举.为了得到它们,你必须使用Object.getOwnPropertyNames:

var propertyNames = Object.getOwnPropertyNames(Object.getPrototypeOf(foo));
// or
var propertyNames = Object.getOwnPropertyNames(Foo.prototype);
Run Code Online (Sandbox Code Playgroud)

当然这不会得到继承的方法.没有任何方法可以为您提供所有这些方法.您必须遍历原型链并单独获取每个原型的属性.

  • 不要忘记`Object.getOwnPropertySymbols`! (4认同)

Muh*_*mer 40

该功能将获得所有功能.是继承与否,可枚举与否.包括所有功能.

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;
    });
}
Run Code Online (Sandbox Code Playgroud)

做测试

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__"]
Run Code Online (Sandbox Code Playgroud)

注意

它不返回通过符号定义的函数;

  • 很好,但过滤器内的`obj`是'null`.如果不是'while`永远不会退出,对:) (3认同)
  • 您还需要`.concat(Object.getOwnPropertySymbols(obj))`,因为`getOwnPropertyNames` 只会返回`string` 键。这意味着您的示例不会选择迭代器函数。 (2认同)
  • 很好的解决方案。如果你想删除像`__defineGetter__`这样的内置东西,你可以做`while ((obj = Object.getPrototypeOf(obj)) && obj != Object.prototype)` (2认同)

ska*_*kav 25

ES6添加了反射,使代码更清洁.

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]);
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案返回了我怀疑人们想要的所有内部方法,你将如何获得声明的方法? (3认同)

Bru*_*der 8

@MuhammadUmer在我的回答中有一些问题(符号,索引i+1,Object方法列表等等),所以从中获取灵感,我想出了这个

(警告打字稿编译到ES6)

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
}
Run Code Online (Sandbox Code Playgroud)

此函数将列出类的实例的所有方法,包括那些继承的方法,但是构造函数和Object原型的那些方法.

测试

该函数返回

[ 'asyncMethod',
  'echo',
  'generatorMethod',
  'ping',
  'pong',
  'anotherEcho' ]
Run Code Online (Sandbox Code Playgroud)

列出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'
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这是一个伟大的片段,它的工作原理.但是,一个小警告:如果对象具有由`Object.defineProperty`或es5-style`get propertyName(){}`定义的属性,它可能无法按预期工作.问题在于`typeof obj [p] ==='function'.事物是属性`obj [p]`getter实际上会被**调用**,但是不正确的`this`.因此,如果属性getter使用`this`,将导致意外结果,例如崩溃.解决方案 - 这里`typeof obj [p] ==='function'`而不是`obj`使用传递给这个`getAllMethods`的原始文件(将它存储在局部变量中). (3认同)