在TypeScript中获取类方法的名称

Col*_*lum 8 javascript regex typescript

对于查看此内容的任何人,此问题类似于以下内容:

如何在JavaScript中获取对象类型的名称?
在TypeScript中运行时获取对象的类名

然而,在一些方面它是不同的.

我希望得到属于类的方法的名称,并将其存储在TypeScript/JavaScript中的变量中.
看看以下设置:

class Foo {

    bar(){
        // logic
    }

}
Run Code Online (Sandbox Code Playgroud)

以上是有效的TypeScript,我想在不同的类中创建一个方法,它将返回bar()方法的名称,"bar"
例如:

class ClassHelper {

    getMethodName(method: any){
        return method.name; // per say
    }

}
Run Code Online (Sandbox Code Playgroud)

我希望能够以ClassHelper下列方式使用:

var foo = new Foo();
var barName = ClassHelper.getMethodName(foo.bar); // "bar"
Run Code Online (Sandbox Code Playgroud)

我看过很多帖子,有些建议使用以下内容:

var funcNameRegex = /function (.{1,})\(/;   
var results = (funcNameRegex).exec(obj.toString());
var result = results && results.length > 1 && results[1];
Run Code Online (Sandbox Code Playgroud)

但由于我的方法没有从function
另一个建议开始,这失败了:

public getClassName() {
    var funcNameRegex = /function (.{1,})\(/;
    var results  = (funcNameRegex).exec(this["constructor"].toString());
    return (results && results.length > 1) ? results[1] : "";
}
Run Code Online (Sandbox Code Playgroud)

这只返回类名,但是从阅读帖子中看来,使用它constructor可能是不可靠的.

此外,当我使用其中一些方法调试代码时,传递方法如下:ClassHelper.getMethodName(foo.bar);如果方法采用一个方法,将导致传递参数,例如:

class Foo {

    bar(param: any){
        // logic
    }

}

var foo = new Foo();
var barName = ClassHelper.getMethodName(foo.bar); // results in param getting passed through
Run Code Online (Sandbox Code Playgroud)

我一直在努力解决这个问题,如果有人有任何关于如何解决这个问题的信息,我将不胜感激.

.toString()传入的方法返回:

.toString() = "function (param) { // code }"
Run Code Online (Sandbox Code Playgroud)

而不是:

.toString() = "function bar(param) { // code }"
Run Code Online (Sandbox Code Playgroud)

根据MDN,它不应该:

也就是说,toString反编译该函数,返回的字符串包括函数关键字,参数列表,花括号和函数体的源.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toString#Description

Tam*_*dus 5

我采纳了约翰·怀特的想法并对其进行了改进,使其适用于我能想到的每种情况。这种方法的优点是运行时不需要解析js代码。但有一种边缘情况,它根本无法推断出正确的属性名称,因为有多个正确的属性名称。

class Foo {
  bar() {}
  foo() {}
}

class ClassHelper {
  static getMethodName(obj, method) {
    var methodName = null;
    Object.getOwnPropertyNames(obj).forEach(prop => {
      if (obj[prop] === method) {
        methodName = prop;
      }
    });

    if (methodName !== null) {
      return methodName;
    }
    
    var proto = Object.getPrototypeOf(obj);
    if (proto) {
      return ClassHelper.getMethodName(proto, method);
    }
    return null;
  }
}

var foo = new Foo();
console.log(ClassHelper.getMethodName(foo, foo.bar));
console.log(ClassHelper.getMethodName(Foo.prototype, foo.bar));
console.log(ClassHelper.getMethodName(Foo.prototype, Foo.prototype.bar));

var edgeCase = { bar(){}, foo(){} };
edgeCase.foo = edgeCase.bar;
console.log(ClassHelper.getMethodName(edgeCase, edgeCase.bar));
Run Code Online (Sandbox Code Playgroud)


Col*_*lum 3

我找到了解决方案。我不确定它的效率和可重用性如何,但它在多个测试用例中有效,包括嵌套方法,例如Class -> Class -> Method

我的解决方案:

class ClassHelpers {
    getName(obj: any): string {    
        if (obj.name) {
            return obj.name;
        }

        var funcNameRegex = /function (.{1,})\(/;   
        var results = (funcNameRegex).exec(obj.toString());
        var result = results && results.length > 1 && results[1];

        if(!result){
            funcNameRegex = /return .([^;]+)/;
            results = (funcNameRegex).exec(obj.toString());
            result = results && results.length > 1 && results[1].split(".").pop();
        }

        return result || "";
    }
}


class Foo {

    bar(param: any){
        // logic
    }

}

var foo = new Foo();
var barName = ClassHelper.getMethodName(() => foo.bar);
Run Code Online (Sandbox Code Playgroud)

lambda 表示法ClassHelper.getMethodName(() => foo.bar);是让它工作的关键,因为它允许.toString()包含return foo.bar;

我要做的下一件事是从其中提取方法调用,.toString()然后我使用数组和字符串函数返回最后一个子字符串,这不可避免地是方法名称。

就像我说的,它可能不是最优雅的解决方案,但它确实有效,甚至适用于嵌套方法

注意:您可以用常规匿名函数替换 lambda 函数

var foo = new Foo();
var barName = ClassHelper.getMethodName(function() { return foo.bar; });
Run Code Online (Sandbox Code Playgroud)