如何从函数内部访问函数名?
// 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();
这可能对你有用:
function foo() { bar(); }
function bar() { console.log(bar.caller.name); }
如果从匿名函数调用,运行foo()将输出“foo”或未定义。
它也适用于构造函数,在这种情况下,它将输出调用构造函数的名称(例如“Foo”)。
更多信息请访问:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller
他们声称这是不标准的,但所有主流浏览器都支持它:Firefox、Safari、Chrome、Opera和IE。
在ES6中,你可以只使用myFunction.name。
注意:为了更好地压缩,一些JS的迷你器可能会丢弃函数名;你可能需要调整他们的设置来避免这种情况。
在ES5中,最好的做法是:
function functionName(fun) {
var ret = fun.toString();
ret = ret.substr('function '.length);
ret = ret.substr(0, ret.indexOf('('));
return ret;
}
使用函数。调用者是非标准的。函数。调用者和实参。在严格模式下,被调用都是被禁止的。
编辑:nus的基于正则表达式的答案实现了同样的事情,但有更好的性能!
ES6(灵感来自sendy halim的回答):
myFunction.name
MDN说明。截至2015年,可以在nodejs和除IE之外的所有主流浏览器上运行。
注意:对于绑定函数,这将给出"bound <originalName>"。如果你想要得到原来的名字,你必须去掉“束缚”。
ES5(灵感来自Vlad的回答):
如果你有一个函数的引用,你可以这样做:
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
}
我没有对此运行单元测试,也没有对实现进行验证
分歧,但原则上应该工作,如果没有留下评论。
注意:不适用于绑定函数
注意:调用者和被调用者被认为已弃用。
我把它放在这里是因为它是合法的,而且经常有足够的语法高亮显示工具没有考虑到函数名和圆括号之间的空白。另一方面,我不知道. tostring()的任何实现会在这里包含空白,所以这就是为什么你可以省略它。
作为对最初问题的回答,我会放弃寄生继承,转而采用一些更传统的OOP设计模式。我写了一篇花絮。OoJs可以轻松地用JavaScript编写OOP代码,并带有模仿c++的特性集(还没有完成,但大部分是)。
我从评论中看到,你想避免传递信息的父需要它的构造函数。我必须承认,传统的设计模式并不能使您摆脱这种情况,因为使您的依赖关系明显和强制通常被认为是一件好事。
我还建议避免使用匿名函数。他们只对PITA进行调试和分析,因为一切都显示为“匿名函数”,据我所知,这对他们没有任何好处。
我也遇到过类似的问题,解决方法如下:
Function.prototype.myname = function() {
return this.toString()
.substr( 0, this.toString().indexOf( "(" ) )
.replace( "function ", "" );
}
这段代码以一种更舒适的方式实现了我已经在讨论的开头读到的一个响应。
现在我有一个成员函数检索任何函数对象的名称。
这是完整的剧本……
<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>
可以使用name属性获取函数名,除非使用匿名函数
例如:
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());
现在让我们试试named function
var Person = function Person () {
this.someMethod = function someMethod() {};
};
现在你可以使用
// will return "someMethod"
p.getSomeMethodName()
这看起来是我这辈子写过的最愚蠢的东西,但很有趣: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 -堆栈深度。0 -返回此函数名,1 -父函数,等等;
[0 + d] -为了理解,会发生什么;
firefoxMatch -适用于safari,但我真的有一点时间测试,因为mac的主人吸烟后回来了,并把我赶走了:'(
测试:
function limbo(){
for(let i = 0; i < 4; i++){
console.log(getName(i));
}
}
function lust(){
limbo();
}
function gluttony(){
lust();
}
gluttony();
结果:
铬:
Fitefox:
这个解决方案只是为了好玩而创造的!不要在实际项目中使用它。它不依赖于ES规范,只依赖于浏览器实现。在下次chrome/firefox/safari更新后,它可能会被破坏。
超过这个数就没有错误(ha)处理-如果d将大于堆栈长度-你将得到一个错误;
对于其他浏览器的错误消息模式-你会得到一个错误;
它必须适用于ES6类(.split('.').pop()),但你仍然可以得到一个错误;