admin管理员组文章数量:1203386
For anyone viewing this, this question is similar to the following:
How do I get the name of an object's type in JavaScript?
Get an object's class name at runtime in TypeScript
However it is different in a few regards.
I'm looking to get the name of method that belongs to a class and store it in a variable in TypeScript / JavaScript.
Take a look at the following setup:
class Foo {
bar(){
// logic
}
}
The above is valid TypeScript and I would like to create a method in a different class that will return me the name of the bar()
method, i.e "bar"
eg:
class ClassHelper {
getMethodName(method: any){
return method.name; // per say
}
}
I would then like to be able to use the ClassHelper
in the following way:
var foo = new Foo();
var barName = ClassHelper.getMethodName(foo.bar); // "bar"
I've looked at a lot of posts, some suggest using the following:
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(obj.toString());
var result = results && results.length > 1 && results[1];
but this fails as my methods do not begin with function
another suggestion was:
public getClassName() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(this["constructor"].toString());
return (results && results.length > 1) ? results[1] : "";
}
This only returns the class name however and from reading posts, it seems using constructor
can be unreliable.
Also, when I've debugged the code using some of these methods, passing in the method like so: ClassHelper.getMethodName(foo.bar);
will result in the parameter being passed if the method takes one, eg:
class Foo {
bar(param: any){
// logic
}
}
var foo = new Foo();
var barName = ClassHelper.getMethodName(foo.bar); // results in param getting passed through
I've been struggling with this for a while, if anyone has any information on how I can solve this it would be greatly appreciated.
My .toString()
on the method passed in returns this:
.toString() = "function (param) { // code }"
rather than:
.toString() = "function bar(param) { // code }"
and according to MDN it isn't supposed to either:
That is, toString decompiles the function, and the string returned includes the function keyword, the argument list, curly braces, and the source of the function body.
For anyone viewing this, this question is similar to the following:
How do I get the name of an object's type in JavaScript?
Get an object's class name at runtime in TypeScript
However it is different in a few regards.
I'm looking to get the name of method that belongs to a class and store it in a variable in TypeScript / JavaScript.
Take a look at the following setup:
class Foo {
bar(){
// logic
}
}
The above is valid TypeScript and I would like to create a method in a different class that will return me the name of the bar()
method, i.e "bar"
eg:
class ClassHelper {
getMethodName(method: any){
return method.name; // per say
}
}
I would then like to be able to use the ClassHelper
in the following way:
var foo = new Foo();
var barName = ClassHelper.getMethodName(foo.bar); // "bar"
I've looked at a lot of posts, some suggest using the following:
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(obj.toString());
var result = results && results.length > 1 && results[1];
but this fails as my methods do not begin with function
another suggestion was:
public getClassName() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec(this["constructor"].toString());
return (results && results.length > 1) ? results[1] : "";
}
This only returns the class name however and from reading posts, it seems using constructor
can be unreliable.
Also, when I've debugged the code using some of these methods, passing in the method like so: ClassHelper.getMethodName(foo.bar);
will result in the parameter being passed if the method takes one, eg:
class Foo {
bar(param: any){
// logic
}
}
var foo = new Foo();
var barName = ClassHelper.getMethodName(foo.bar); // results in param getting passed through
I've been struggling with this for a while, if anyone has any information on how I can solve this it would be greatly appreciated.
My .toString()
on the method passed in returns this:
.toString() = "function (param) { // code }"
rather than:
.toString() = "function bar(param) { // code }"
and according to MDN it isn't supposed to either:
Share Improve this question edited May 23, 2017 at 12:00 CommunityBot 11 silver badge asked Jun 30, 2016 at 8:46 ColumColum 9862 gold badges9 silver badges23 bronze badgesThat is, toString decompiles the function, and the string returned includes the function keyword, the argument list, curly braces, and the source of the function body.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toString#Description
6 Answers
Reset to default 5I have taken John White's idea and improved it so it works for every case I could think of. This method has the advantage of not needing to parse js code at runtime. There is an edge case though, where it simply can't deduce the right property name because there are multiple right property names.
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));
I found a solution. I'm not sure how efficient and reusable it is, but it worked in multiple test cases, included nested methods, eg Class -> Class -> Method
My solution:
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);
The lambda notation ClassHelper.getMethodName(() => foo.bar);
was key to getting this to work as it allowed the .toString()
to contain return foo.bar;
The next thing I had to do was to extract the method call from the .toString()
then I used array and string functions to return the last substring which inevitably is the method name.
Like I said, it's probably not the most elegant solution but it has worked and even worked for nested methods
NOTE: You can replace the lambda function with a regular anonymous function
var foo = new Foo();
var barName = ClassHelper.getMethodName(function() { return foo.bar; });
Unfortunately, the name of Typescript class methods is lost when compiling to JS (as you correctly inferred). Typescript methods are compiled to Javascript by adding the method to the prototype of a Javascript class. (Check the compiled Javascript for more info).
In Javascript, this works:
Foo.prototype["bar"] // returns foo.bar <<the function>>
So, the thing you could think of is reversing the prototype of the class, so the class itself becomes the key of the object:
Foo.prototype[foo.bar] // return "bar"
Of course, this is a very hacky solution, since
- Complexity is
O(N)
(loop through array) - I'm not sure this works in every case.
(Working) Example for your problem:
class Foo{
bar(){}
}
class ClassHelper{
static reversePrototype(cls:any){
let r = {};
for (var key in cls.prototype){
r[cls.prototype[key]] = key;
}
return r;
}
static getMethodNameOf(cls: any, method:any):string{
let reverseObject = ClassHelper.reversePrototype(cls);
return reverseObject[method];
}
}
var foo = new Foo();
console.log(ClassHelper.getMethodNameOf(Foo, foo.bar)) // "bar"
The better solution would be a typescript compiler option that changes the way typescript transpiles classes to javascript. However, I'm currently not aware of any option that does this sort of thing.
You could pass in both the object and the method, get the array of property keys on the object, then using property keys see if each given property is the same object reference as the supplied method -- and if so, there is a match.
class ClassHelper {
getMethodName(obj: any, method: any) {
var methodName: string;
if (method) {
Object.keys(obj).forEach(key => {
if (obj[key] === method) {
methodName = key;
}
});
}
return methodName;
}
}
This has the downside that the host object must also be known. If the method cannot be found, undefined
will be returned.
Object.keys may help you. Try this way
class Greeter {
test : Function;
constructor(message: string) {
this.test = function(){
return message;
}
}
}
var a = new Greeter("world");
var properties = Object.keys(a);
alert(properties.join(', ')); //test
Hi I have been making some testing and I founded a simpler solution.
class Parent{
constructor(){
// here you initialize your stuff
}
parentMethod1 (){ return "I am method 1" }
parentMethod2 (){ return "I am method 2" }
}
class Child extends Parent{
constructor(){
// make this if you want to pass extra args to parent class
super()
}
childMethod1(){ /*child actions*/ }
childMethod2(){ /* other child actions */ }
}
const parent = new Parent();
const child = new Child();
console.log( Object.getOwnPropertyNames(parent.__proto__)) // --> ["constructor", "parentMethod1", "parentMethod2"]
console.log(Object.getOwnPropertyNames(child.__proto__)) //--> ["constructor", "childMethod1","childMethod2"]
console.log(parent.constructor.name) // --> Parent
console.log(child.constructor.name) // --> Child
本文标签: javascriptGet name of class method in TypeScriptStack Overflow
版权声明:本文标题:javascript - Get name of class method in TypeScript - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1738663081a2105539.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论