可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
How can I access a function name from inside that function?
// parasitic inheritance
var ns.parent.child = function() {
var parent = new ns.parent();
parent.newFunc = function() {
}
return parent;
}
var ns.parent = function() {
// at this point, i want to know who the child is that called the parent
// ie
}
var obj = new ns.parent.child();
回答1:
In ES5, the best thing to do is:
function functionName(fun) {
var ret = fun.toString();
ret = ret.substr(\'function \'.length);
ret = ret.substr(0, ret.indexOf(\'(\'));
return ret;
}
Using Function.caller
is non-standard. Function.caller
and arguments.callee
are both forbidden in strict mode.
Edit: nus\'s regex based answer below achieves the same thing, but has better performance!
In ES6, you can just use myFunction.name
.
Note: Beware that some JS minifiers might throw away function names, to compress better; you may need to tweak their settings to avoid that.
回答2:
ES6 (inspired by sendy halim\'s answer below):
myFunction.name
Explanation on MDN. As of 2015 works in nodejs and all major browsers except IE.
Note: On bound functions this will give \"bound <originalName>
\". You will have to strip the \"bound \" if you want to get the original name.
ES5 (inspired by Vlad\'s answer):
If you have a reference to the function, you can do:
function functionName( func )
{
// Match:
// - ^ the beginning of the string
// - function the word \'function\'
// - \\s+ at least some white space
// - ([\\w\\$]+) capture one or more valid JavaScript identifier characters
// - \\s* optionally followed by white space (in theory there won\'t be any here,
// so if performance is an issue this can be omitted[1]
// - \\( followed by an opening brace
//
var result = /^function\\s+([\\w\\$]+)\\s*\\(/.exec( func.toString() )
return result ? result[ 1 ] : \'\' // for an anonymous function there won\'t be a match
}
- I have not run unit tests on this, or verified implementation
differences, but in principle it should work, if not leave a comment.
- Note: won\'t work on bound functions
- Note: that
caller
and callee
are considered deprecated.
[1] I include it here because it is legal and often enough syntax highlighting tools fail to take into account the white space between function name and parenthesis. On the other hand, I\'m not aware of any implementation of .toString() that will include white space here, so that\'s why you can omit it.
As an answer to the original question, I would drop parasitic inheritance and go for some more traditional OOP design patterns. I wrote a TidBits.OoJs to comfortably write OOP code in JavaScript with a feature set mimicking C++ (not yet complete, but mostly).
I see from the comments that you would like to avoid passing information parent
needs to it\'s constructor. I must admit that traditional design patterns won\'t save you from that one though, since it is generally a considered a good thing to make your dependencies obvious and enforced.
I would also suggest to steer away from anonymous functions. They only make debugging and profiling a PITA because everything just shows up as \"anonymous function\", and there is no benefit to them that I\'m aware of.
回答3:
what you\'re doing is assigning unnamed function to a variable. you probably need named function expression instead ( http://kangax.github.com/nfe/ ).
var x = function x() {
console.log( arguments.callee.name );
}
x();
however I\'m not sure how much cross-browser that is; there\'s an issue with IE6 that makes you function\'s name leak to the outer scope. also, arguments.callee is kind of deprecated and will result in error if you\'re using strict mode
.
回答4:
Any constructor
exposes a property name
, which is the function name. You access the constructor
via an instance (using new
) or a prototype
:
function Person() {
console.log(this.constructor.name); //Person
}
var p = new Person();
console.log(p.constructor.name); //Person
console.log(Person.prototype.constructor.name); //Person
回答5:
This might work for you:
function foo() { bar(); }
function bar() { console.log(bar.caller.name); }
running foo() will output \"foo\" or undefined if you call from an anonymous function.
It works with constructors too, in which case it would output the name of the calling constructor (eg \"Foo\").
More info here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller
They claim it\'s non-standard, but also that it\'s supported by all major browsers: Firefox, Safari, Chrome, Opera and IE.
回答6:
You can\'t. Functions don\'t have names according to the standard (though mozilla has such an attribute) - they can only be assigned to variables with names.
Also your comment:
// access fully qualified name (ie \"my.namespace.myFunc\")
is inside the function my.namespace.myFunc.getFn
What you can do is return the constructor of an object created by new
So you could say
var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
回答7:
You can use name
property to get the function name, unless you\'re using an anonymous function
For example:
var Person = function Person () {
this.someMethod = function () {};
};
Person.prototype.getSomeMethodName = function () {
return this.someMethod.name;
};
var p = new Person();
// will return \"\", because someMethod is assigned with anonymous function
console.log(p.getSomeMethodName());
now let\'s try with named function
var Person = function Person () {
this.someMethod = function someMethod() {};
};
now you can use
// will return \"someMethod\"
p.getSomeMethodName()
回答8:
You could use Function.name
:
In most implementations of JavaScript, once you have your constructor\'s reference in scope, you can get its string name from its name property (e.g. Function.name, or Object.constructor.name
You could use Function.callee
:
The native arguments.caller
method has been deprecated, but most browsers support Function.caller
, which will return the actual invoking object (its body of code):
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller
You could create a source map:
If what you need is the literal function signature (the \"name\" of it) and not the object itself, you might have to resort to something a little more customized, like creating an array reference of the API string values you\'ll need to access frequently. You can map them together using Object.keys()
and your array of strings, or look into Mozilla\'s source maps library on GitHub, for bigger projects:
https://github.com/mozilla/source-map
回答9:
You could use this, but it\'s not for all browsers, only the ones that support Error.stack
function VamosRafa(){
var a = new Error().stack.match(/at (.*?) /);
console.log(a[1]);
}
VamosRafa();
Of course this is for the current function, but you get the idea.
Cheers!
回答10:
as part as ECMAScript 6
you can use Function.name method
function doSomething() {}
alert(doSomething.name); // alerts \"doSomething\"
回答11:
It looks like the most stupid thing, that I wrote in my life, but it\'s funny :D
function getName(d){
const error = new Error();
const firefoxMatch = (error.stack.split(\'\\n\')[0 + d].match(/^.*(?=@)/) || [])[0];
const chromeMatch = ((((error.stack.split(\'at \') || [])[1 + d] || \'\').match(/(^|\\.| <| )(.*[^(<])( \\()/) || [])[2] || \'\').split(\'.\').pop();
const safariMatch = error.stack.split(\'\\n\')[0 + d];
// firefoxMatch ? console.log(\'firefoxMatch\', firefoxMatch) : void 0;
// chromeMatch ? console.log(\'chromeMatch\', chromeMatch) : void 0;
// safariMatch ? console.log(\'safariMatch\', safariMatch) : void 0;
return firefoxMatch || chromeMatch || safariMatch;
}
d
- depth of stack. 0
- return this function name, 1
- parent, etc.;
[0 + d]
- just for understanding - what happens;
firefoxMatch
- works for safari, but I had really a little time for testing, because mac\'s owner had returned after smoking, and drove me away :\'(
Testing:
function limbo(){
for(let i = 0; i < 4; i++){
console.log(getName(i));
}
}
function lust(){
limbo();
}
function gluttony(){
lust();
}
gluttony();
Result:
Chrome:
Fitefox:
This solution was creating only just for fun! Dont use it for real projects. It not depends on ES specification, it depends only on browser realisation. After next chrome/firefox/safari update it may be broken.
More than that there is no error (ha) processing - if d
will be more than stack length - you will get an error;
For other wrowsers error\'s messaage pattern - you will get an error;
It must work for ES6 classes (.split(\'.\').pop()
), but you sill can get an erorr;
回答12:
You can use constructor name like:
{your_function}.prototype.constructor.name
this code simply return name of a method.
回答13:
I know this is a old question but lately I\'ve been facing some similar issue while trying to decorate some React Component\'s methods, for debugging purposes. As people already said, arguments.caller
and arguments.callee
are forbidden in strict mode which is probably enabled by default in your React transpiling. You can either disable it, or I\'ve been able to come up with another hack, because in React all class functions are named, you can actually do this:
Component.prototype.componentWillMount = function componentWillMount() {
console.log(\'Callee name: \', this.__proto__.constructor.toString().substr(0,30));
...
}
回答14:
look here: http://www.tek-tips.com/viewthread.cfm?qid=1209619
arguments.callee.toString();
seems to be right for your needs.
回答15:
This worked for me.
function AbstractDomainClass() {
this.className = function() {
if (!this.$className) {
var className = this.constructor.toString();
className = className.substr(\'function \'.length);
className = className.substr(0, className.indexOf(\'(\'));
this.$className = className;
}
return this.$className;
}
}
Test code:
var obj = new AbstractDomainClass();
expect(obj.className()).toBe(\'AbstractDomainClass\');
回答16:
I had a similar problem and I solved it as follows:
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( \"(\" ) )
.replace( \"function \", \"\" );
}
This code implements, in a more comfortable fashion, one response I already read here at the top of this discussion.
Now I have a member function retrieving the name of any function object.
Here\'s the full script ...
<script language=\"javascript\" TYPE=\"text/javascript\">
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( \"(\" ) )
.replace(\"function \", \"\" );
}
function call_this( _fn ) { document.write( _fn.myname() ); }
function _yeaaahhh() { /* do something */ }
call_this( _yeaaahhh );
</script>
回答17:
you can use Error.stack to trace the function name and exact position of where you are in it.
See stacktrace.js
回答18:
Easy way to get function name from within fuction you are running.
function x(){alert(this.name)};x()