如何从该函数中获取函数名?

时间:2010-04-15 19:19:31

标签: javascript 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();

21 个答案:

答案 0 :(得分:151)

在ES5中,最好的办法是:

function functionName(fun) {
  var ret = fun.toString();
  ret = ret.substr('function '.length);
  ret = ret.substr(0, ret.indexOf('('));
  return ret;
}

使用Function.caller是非标准的。 <{1}}和Function.caller都是严格禁止的。

编辑:下面的nus基于正则表达式的答案实现了同样的目的,但性能更好!

在ES6中,您只需使用arguments.callee

注意:请注意一些JS minifiers可能会丢弃函数名称,以便更好地压缩;你可能需要调整他们的设置以避免这种情况。

答案 1 :(得分:120)

ES6 (灵感来自下面的sendy halim的答案):

myFunction.name

Explanation on MDN。截至2015年,在nodejs和除IE之外的所有主要浏览器中都可以使用。

注意:在绑定函数上,这将给出“bound <originalName>”。如果要获取原始名称,则必须剥离“绑定”。


ES5 (受弗拉德回答的启发):

如果你有这个功能的参考,你可以这样做:

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
}
  • 我没有对此进行单元测试或验证实现 差异,但原则上它应该有效,如果不发表评论。
  • 注意:不适用于绑定函数
  • 注意:callercallee被视为已弃用。

[1] 我在此处包含它是因为它是合法的,并且通常足够的语法突出显示工具无法考虑函数名称和括号之间的空白。另一方面,我不知道.toString()的任何实现都包含空格,所以你可以省略它。


作为原始问题的答案,我会放弃寄生继承并寻求更传统的OOP设计模式。我写了一个TidBits.OoJs来轻松地在JavaScript中编写OOP代码,其中包含一个模仿C ++的功能集(尚未完成,但主要是)。

我从评论中看到,您希望避免将信息parent需要传递给它的构造函数。我必须承认,传统的设计模式不会让你远离那个,因为通常认为你的依赖关系是显而易见的并且是强制性的。

我还建议远离匿名函数。他们只对PITA进行调试和分析,因为所有内容都只是显示为“匿名函数”,而我所知道的对他们没有任何好处。

答案 2 :(得分:52)

您正在做的是将未命名的函数分配给变量。你可能需要命名函数表达式(http://kangax.github.com/nfe/)。

var x = function x() {
    console.log( arguments.callee.name );
}
x();

然而我不确定那是多少跨浏览器; IE6存在一个问题,它使您的函数名称泄漏到外部作用域。另外,arguments.callee有点不推荐使用,如果您使用的是strict mode,则会导致错误。

答案 3 :(得分:17)

任何constructor都会公开属性name,这是函数名称。您可以通过实例(使用constructor)或new访问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

答案 4 :(得分:14)

这可能对您有用:

function foo() { bar(); }

function bar() { console.log(bar.caller.name); }

如果从匿名函数调用,运行foo()将输出“foo”或undefined。

它也适用于构造函数,在这种情况下,它将输出调用构造函数的名称(例如“Foo”)。

此处有更多信息:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller

他们声称这是非标准的,但它也受到所有主流浏览器的支持:Firefox,Safari,Chrome,Opera和IE。

答案 5 :(得分:8)

你做不到。函数没有根据标准的名称(虽然mozilla具有这样的属性) - 它们只能分配给具有名称的变量。

还有你的评论:

// access fully qualified name (ie "my.namespace.myFunc")

位于my.namespace.myFunc.getFn函数

您可以做的是返回由新

创建的对象的构造函数

所以你可以说

var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc

答案 6 :(得分:7)

这看起来像是我生命中写的最愚蠢的事情,但这很有趣: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 - parent等;
[0 + d] - 只是为了理解 - 会发生什么;
firefoxMatch - 适用于野生动物园,但我确实有一点时间进行测试,因为mac的主人在吸烟后回来了,并把我赶走了:'(

测试:

function limbo(){
  for(let i = 0; i < 4; i++){
    console.log(getName(i));
  }
}
function lust(){
  limbo();
}
function gluttony(){
  lust();
}

gluttony();

<强>结果:
铬:
enter image description here

Fitefox:
enter image description here

此解决方案只是为了娱乐而创建 !不要用它来做真正的项目。它不依赖于ES规范,它仅取决于浏览器的实现。在下一次chrome / firefox / safari更新后,它可能会被破坏 不仅如此,没有错误(ha)处理 - 如果d将超过堆栈长度 - 您将收到错误;
对于其他wrowsers错误的消息模式 - 你会得到一个错误;
它必须适用于ES6类(.split('.').pop()),但你可以得到一个erorr;

答案 7 :(得分:4)

您可以使用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());

现在让我们试试命名函数

var Person = function Person () {
  this.someMethod = function someMethod() {};
};

现在可以使用

// will return "someMethod"
p.getSomeMethodName()

答案 8 :(得分:3)

您可以使用Function.name

在JavaScript的大多数实现中,一旦在范围内有构造函数的引用,就可以从其name属性中获取其字符串名称(例如Function.name或Object.constructor.name

您可以使用Function.callee

本地arguments.caller方法已被弃用,但大多数浏览器都支持Function.caller,它将返回实际的调用对象(其代码体): 的 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller

您可以创建源地图

如果你需要的是文字函数签名(它的“名称”)而不是对象本身,你可能不得不诉诸一些更自定义的东西,比如创建一个API字符串值的数组引用''我需要经常访问。你可以使用Object.keys()和你的数组字符串将它们映射到一起,或者在GitHub上查看Mozilla的源映射库,以获得更大的项目: 的 https://github.com/mozilla/source-map

答案 9 :(得分:3)

您可以使用以下构造函数名称:

{your_function}.prototype.constructor.name

此代码仅返回方法的名称。

答案 10 :(得分:3)

您可以使用此功能,但并非适用于所有浏览器,只适用于支持Error.stack的浏览器

function VamosRafa(){ 
  var a = new Error().stack.match(/at (.*?) /);
  console.log(a[1]);
} 
VamosRafa();

当然这是针对当前的功能,但你明白了。

干杯!

答案 11 :(得分:3)

作为ECMAScript 6的一部分,您可以使用Function.name方法

function doSomething() {}

alert(doSomething.name); // alerts "doSomething"

答案 12 :(得分:2)

我知道这是一个老问题,但最近我在尝试修饰某些React Component的方法时遇到了类似的问题,以便进行调试。正如人们已经说过的那样,arguments.callerarguments.callee在严格模式下被禁止,默认情况下可能在您的React转换中启用。您可以禁用它,或者我已经能够提出另一个hack,因为在React中所有类函数都已命名,您实际上可以这样做:

Component.prototype.componentWillMount = function componentWillMount() {
    console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}

答案 13 :(得分:1)

动态检索函数名称(如魔术变量)的一个简单解决方案是使用作用域变量。

{
  function parent() {
    console.log(a.name);
  }; let a = parent
}
{
  function child() {
    console.log(a.name)
  }; let a = child
};

parent();//logs parent
child();//logs child

注意:嵌套函数不再是源元素,因此不会被提升。 此外,这种技术不能用于匿名函数。

答案 14 :(得分:1)

如果我了解您想要做什么,这就是我在函数构造函数中要做的事情。

if (!(this instanceof arguments.callee)) {
    throw "ReferenceError: " + arguments.callee.name + " is not defined";
}

答案 15 :(得分:1)

这对我有用。

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;
    }
}

测试代码:

var obj = new AbstractDomainClass();
expect(obj.className()).toBe('AbstractDomainClass');

答案 16 :(得分:1)

我遇到了类似的问题,我解决了以下问题:

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>

答案 17 :(得分:0)

这将在ES5,ES6,所有浏览器和严格模式下运行。

这是命名函数的外观。

(function myName() {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at myName (<anonymous>:2:15)

使用匿名函数的外观如下。

(() => {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at <anonymous>:2:15

答案 18 :(得分:-1)

您可以使用Error.stack跟踪函数名称以及您所在位置的确切位置。

请参阅stacktrace.js

答案 19 :(得分:-1)

看这里:http://www.tek-tips.com/viewthread.cfm?qid=1209619

arguments.callee.toString();

似乎适合您的需求。

答案 20 :(得分:-3)

从正在运行的功能中获取功能名称的简便方法。

function x(){alert(this.name)};x()