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

Sco*_*ach 242 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();
Run Code Online (Sandbox Code Playgroud)

Vla*_*scu 157

在ES5中,最好的办法是:

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

使用Function.caller是非标准的.Function.caller并且arguments.callee在严格模式下都被禁止.

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

在ES6中,您可以使用myFunction.name.

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

  • 如果输入函数名,那么`myFunction.name`有什么意义?打败魔术变量的目的. (11认同)
  • @adi518:不一定.. 假设您有任何函数数组并且您对其进行迭代,使用 for/foreach ..那么 `arr[index].name` 也将起作用:) (6认同)
  • 在ES6中,Yup`myFunction.name`是最好的选择. (3认同)
  • @adi518 这并不是没有用。如果我在 IDE 中重命名该函数,“myFunction.name”也会更新。当然,intelliJ 支持在字符串中重命名标识符,但是这种方法的一致性较差,并且如果有人忘记勾选“在字符串中搜索”选项,它就会默默地变得过时。`myFunction.name` 是比硬编码字符串稍好的选择。 (3认同)

小智 127

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

myFunction.name
Run Code Online (Sandbox Code Playgroud)

关于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
}
Run Code Online (Sandbox Code Playgroud)
  • 我没有对此进行单元测试,或者验证了实现差异,但原则上它应该可行,如果不发表评论.
  • 注意:不适用于绑定函数
  • 注意:那caller并且callee被认为已弃用.

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


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

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

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

  • 不错的RegEx!这是一个性能测试,显示您的代码在许多情况下是最快的.一般情况下,RegEx似乎平均以2倍的速度击败原生JS.http://jsperf.com/get-function-name/2 (3认同)

wil*_*ard 57

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

var x = function x() {
    console.log( arguments.callee.name );
}
x();
Run Code Online (Sandbox Code Playgroud)

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

  • 这不适用于旧版本的 Safari 浏览器。 (2认同)
  • `arguments.callee` 在严格模式下是被禁止的,但谁在乎——&gt; 加一。 (2认同)

rol*_*and 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
Run Code Online (Sandbox Code Playgroud)

  • 第一个`console.log`调用会根据我在哪里运行而不是`Person`来为我记录`window`或`Object`。 (4认同)

Jac*_*uka 14

这可能对你有用:

function foo() { bar(); }

function bar() { console.log(bar.caller.name); }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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


no_*_*ord 9

对于支持 Error.stack 的浏览器,您可以使用它(可能不是几乎所有)

function WriteSomeShitOut(){ 
  var a = new Error().stack.match(/at (.*?) /);
  console.log(a[1]);
} 
WriteSomeShitOut();
Run Code Online (Sandbox Code Playgroud)

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

写代码时开心流口水


use*_*966 9

看起来是我一生中最愚蠢的事情,但这很有趣: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;
}
Run Code Online (Sandbox Code Playgroud)

d-堆栈深度。0-返回此函数名称,1-父级,等等;
[0 + d]-只是为了理解-会发生什么;
firefoxMatch-适用于野生动物园,但是我确实有一点时间进行测试,因为mac的所有者吸烟后已经回来了,开车把我赶走了:'(

测试:

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

gluttony();
Run Code Online (Sandbox Code Playgroud)

结果:
Chrome:
在此处输入图片说明

Fitefox:
在此处输入图片说明

这个解决方案只是为了好玩而已!不要在实际项目中使用它。它不取决于ES规范,而仅取决于浏览器的实现。下次chrome / firefox / safari更新后,它可能会损坏。
除此之外,没有错误(ha)处理-如果d将超过堆栈长度-您将得到一个错误;
对于其他Wrowsers错误的消息模式-您将得到一个错误;
它必须适用于ES6类(.split('.').pop()),但您可能会犯错;

  • 这是函数名称的一些激烈选择:p (3认同)

plo*_*der 8

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

还有你的评论:

// access fully qualified name (ie "my.namespace.myFunc")
Run Code Online (Sandbox Code Playgroud)

在函数my.namespace.myFunc.getFn中

你可以做的是返回由new创建的对象的构造函数

所以你可以说

var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
Run Code Online (Sandbox Code Playgroud)


sen*_*lim 6

您可以使用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());
Run Code Online (Sandbox Code Playgroud)

现在让我们尝试命名函数

var Person = function Person () {
  this.someMethod = function someMethod() {};
};
Run Code Online (Sandbox Code Playgroud)

现在你可以使用

// will return "someMethod"
p.getSomeMethodName()
Run Code Online (Sandbox Code Playgroud)


Ben*_*nny 5

你可以使用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/函数/调用者?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller

您可以创建一个源映射

如果您需要的是文字函数签名(它的“名称”)而不是对象本身,则您可能不得不求助于一些更自定义的东西,例如创建您需要的 API 字符串值的数组引用频繁访问。您可以使用Object.keys()和您的字符串数组将它们映射在一起


ple*_*ock 5

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

function doSomething() {}

alert(doSomething.name); // alerts "doSomething"
Run Code Online (Sandbox Code Playgroud)

  • 这是函数之外的 (14认同)
  • 在ReactJS中你需要添加这个:console.log(this.doSomething.name); (2认同)

小智 5

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

{your_function}.prototype.constructor.name
Run Code Online (Sandbox Code Playgroud)

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