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

IT技术 javascript function
2021-01-23 18:11:27

如何从该函数内部访问函数名称?

// 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();
6个回答

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

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

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

@ adi518 这不是没用。如果我在我的 IDE 中重命名函数,myFunction.name也会更新。当然,intelliJ 支持重命名字符串中的标识符,但这种方法的一致性要差得多,而且如果有人忘记勾选“在字符串中搜索”选项,那么它就会悄悄地过时。myFunction.name是比硬编码字符串更好的选择。
2021-03-13 18:11:27
是啊myFunction.name是ES6做的最好的事情。
2021-03-28 18:11:27
虽然这对我来说并没有充分回答这个问题(由于匿名函数),但它确实让我想到这样做:fun.toString().substr(0, 100)根据我的需要,这足以找到有问题的函数。所以,谢谢你的灵感!
2021-03-30 18:11:27
@adi518:不一定.. 假设您有任何函数数组并且您对其进行迭代,使用 for/foreach ..thenarr[index].name也可以:)
2021-03-30 18:11:27
是什么在点myFunction.name如果键入功能的名称?违背了魔法变量的目的。
2021-04-07 18:11:27

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

myFunction.name

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

[1] 我把它包含在这里是因为它是合法的,而且语法高亮工具通常没有考虑到函数名和括号之间的空格。另一方面,我不知道 .toString() 的任何实现会在此处包含空格,因此您可以省略它。


作为对原始问题的回答,我将放弃寄生继承并采用一些更传统的 OOP 设计模式。我写了一个TidBits.OoJs来舒适地用 JavaScript 编写 OOP 代码,其中包含模仿 C++ 的功能集(尚未完成,但主要是)。

我从评论中看到您希望避免将信息parent需求传递给它的构造函数。我必须承认,虽然传统设计模式不会让您免于这种情况,因为通常认为使您的依赖项显而易见并强制执行是一件好事。

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

请注意,如果您使用的是 React Native,这可能无法正常工作。我有一个 RN 项目,我正在使用 expo version 36 并且组件方法的.name属性显示为字符串“value”,无论它被称为什么。奇怪的是,在 expo 应用程序中测试时它很好,但是,一旦编译到真正的应用程序中,它就会无声地崩溃。
2021-03-23 18:11:27
不错的正则表达式!这是一个性能测试,表明您的代码在许多情况下是最快的。总的来说,RegEx 在这里以大约 2 倍的速度击败原生 JS。jsperf.com/get-function-name/2
2021-03-28 18:11:27
@Tomasz 嗨,感谢您指出这一点。我不知道。绑定函数实际上是一个新函数,它包装了您的原始函数。ecmascript 标准 § 19.2.3.2 定义新函数的名称应为“bound”+ originalName。toString 方法也不适用于绑定函数...您将不得不去除绑定的单词。
2021-03-31 18:11:27
如果键入函数名,myFunction.name 中有什么意义?违背了魔法变量的目的。
2021-04-09 18:11:27

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

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

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

这不适用于旧版本的 Safari 浏览器。
2021-03-13 18:11:27

Anyconstructor公开一个属性name,即函数名称。您可以constructor通过实例(使用new)或 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
第一次console.log通话记录windowObject对我而言取决于我在哪里运行它,而不是Person.
2021-03-13 18:11:27
您确定使用“new”进行实例化吗?否则无法工作。
2021-04-01 18:11:27

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

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

飞狐:
在此处输入图片说明

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

它类似于 类似于回答stackoverflow.com/questions/38435450/...
2021-03-13 18:11:27