I would like to get the name of the method inside the method in a class and throw an error when one argument is passed to the method. For example, if the name of the instance is instance_of_cookie
and the name of the method is (for simplicity) the_method
, then passing one argument to that method should throw an error like "instance_of_cookie.the_method" expected two arguments
or simply "the_method" expected two arguments
.
I can get the name of the function inside the function using arguments.calle.name
. But that doesn't seem to work inside class methods and throws the following error:
VM10:4 Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
at Cookie.the_method (<anonymous>:4:28)
at eval (eval at the_method (:4:28), <anonymous>:1:32)
at Cookie.the_method (<anonymous>:4:28)
at <anonymous>:13:32
I came across a post which mentioned this.constructor.name
but that gives me the name of the class.
class Cookie {
the_method(x, y) {
if (y == undefined) {
return `'${this.constructor.name}' expects two arguments; one was given`;
} else {
return "Everything's OK"
}
}
}
let instance_of_cookie = new Cookie();
console.log(instance_of_cookie.the_method(8))
Is there any way I can get the name of the method inside the method in a class?
(Note: I can hard-code the name of the method, but for some reasons, I don't want to do that.)
CodePudding user response:
This seems like a complete hack and probably isn't the best solution, but you could use this. I create an error object and use regex to pull the name of the method off the call stack:
class Cookie {
the_method(x, y) {
//regular expression to capture the method name
const reg = new RegExp("(" `${this.constructor.name}` "\.[A-Z|a-z|0-9|_] )", 'g');
if (y == undefined) {
//create an error object
var err = new Error();
//capture matches with regex
const matches = err.stack.match(reg);
//get the method name
const methodname = matches[0].replace(`${this.constructor.name}` '.', '');
return `${methodname} expects two arguments; one was given`;
} else {
return "Everything's OK"
}
}
}
let instance_of_cookie = new Cookie();
console.log(instance_of_cookie.the_method(8))
CodePudding user response:
Instead of dynamically getting the name, you can use a string (which you can change in a later iteration of your program and also use in other places in your code) to define the function name and the method name on the class during construction:
References:
'use strict';
class Example {
constructor () {
const methodName = 'getName';
const selfReferencingMethodWhoseNameMightChangeInTheFuture = (options) => {
if (options?.throw) throw new Error('Oops');
const name = options?.divulge ? methodName : 'Anonymous';
console.log(`My name is "${name}"`);
};
// set the function name for stack diagnostics, etc.
Object.defineProperty(
selfReferencingMethodWhoseNameMightChangeInTheFuture,
'name',
{
// use existing descriptor details
...Object.getOwnPropertyDescriptor(selfReferencingMethodWhoseNameMightChangeInTheFuture, 'name'),
// but update the name
value: methodName,
},
);
this[methodName] = selfReferencingMethodWhoseNameMightChangeInTheFuture;
}
}
const example = new Example();
example.getName(); // My name is "Anonymous"
example.getName({divulge: true}); // My name is "getName"
console.log(example.getName.name); // getName
try {
example.getName({throw: true});
}
catch (ex) {
if (ex instanceof Error) {
// Needed for the Stack Overflow code snippet demo environment
// because it reformats error messages in its virtual console
console.error(ex.stack);
}
else throw ex;
}
Using this technique, you could easily define the name outside the class (or even export it from your module so that — at other call sites in dependent code — invocations can take place dynamically without knowing the method name. Example:
import {Example, methodName} from './very-dynamic-class-module.js';
const example = new Example();
example[methodName]({divulge: true});
Obligatory warning: If you use source transformation tools during build (e.g. minifiers, etc.) which rewrite variable names, be sure to test the interaction with this technique.
CodePudding user response:
No, there's no (non-hacky) way to do that. Just hardcode the name, or if you think that's a refactoring hazard, refer to the method's .name
:
class Cookie {
theMethod(x, y) {
if (y == undefined) {
return `'${this.theMethod.name}' expects two arguments; one was given`;
} else {
return "Everything's OK"
}
}
}
const cookie = new Cookie();
console.log(cookie.theMethod(8))