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

Javascript 如何从该函数中获取函数名?,javascript,function,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 ca

如何从函数内部访问函数名

// 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();

你不能。根据标准,函数没有名称(尽管mozilla有这样一个属性)——它们只能分配给具有名称的变量

还有你的评论:

// access fully qualified name (ie "my.namespace.myFunc")
在函数my.namespace.myFunc.getFn中

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

所以你可以说

var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc
看这里:


似乎适合您的需要。

这可能适合您:

function foo() { bar(); }

function bar() { console.log(bar.caller.name); }
如果从匿名函数调用,运行foo()将输出“foo”或未定义

(function myName() {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
(() => {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
它也与构造函数一起工作,在这种情况下,它将输出调用构造函数的名称(例如“Foo”)

更多信息请点击此处:


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

您所做的是将未命名的函数分配给变量。您可能需要命名函数表达式来代替()


然而,我不确定这是多少跨浏览器;IE6存在一个问题,使函数名泄漏到外部范围。另外,arguments.callee有点不推荐使用,如果您在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下面基于正则表达式的答案实现了同样的效果,但性能更好

您可以使用
函数。名称

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


您可以使用
函数。被调用方

本机
参数.caller
方法已被弃用,但大多数浏览器支持
函数.caller
,该函数将返回实际调用对象(其代码体):

您可以创建源地图

如果您需要的是文本函数签名(它的“名称”)而不是对象本身,那么您可能需要求助于一些更为定制的方法,例如创建需要经常访问的API字符串值的数组引用。您可以使用
object.keys()将它们映射在一起
和您的字符串数组

ES6(受sendy halim下面回答的启发):

.截至2015年,可在nodejs和除IE以外的所有主要浏览器中使用

注意:在绑定函数上,这将给出“
绑定”
”。如果要获得原始名称,必须去掉“绑定”


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
}
  • 我还没有对此运行单元测试,也没有验证实现 分歧,但原则上应该是可行的,如果不留下评论的话
  • 注意:不适用于绑定函数
  • 注意:
    调用者
    被调用者
    被视为不推荐使用
[1]我将其包含在这里是因为它是合法的,而且语法高亮工具常常没有考虑函数名和括号之间的空白。另一方面,我不知道.toString()的任何实现会在这里包含空白,所以可以省略它


作为对原始问题的回答,我会放弃寄生继承,并去寻找一些更传统的OOP设计模式。我用一个模仿C++的特征集(还没有完成,但大部分)编写了一个在JavaScript中轻松编写OOP代码的脚本。 我从评论中看到,您希望避免将父级所需的信息传递给它的构造函数。但我必须承认,传统的设计模式不会将您从中解救出来,因为通常认为,使依赖关系变得明显和强制是一件好事


我还建议远离匿名函数。它们只将调试和分析作为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>

Function.prototype.myname=函数(){
返回此.toString()
.substr(0,this.toString().indexOf(“”)
.replace(“函数”、“函数”);
}
函数调用_this(_fn){document.write(_fn.myname());}
函数_yeaahh(){/*做点什么*/}
叫你这个(_yeaaahh);
这对我很有效

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');

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

对于支持Error.stack的浏览器,您可以使用它(可能不是全部)

当然,这是针对当前函数的,但是您已经明白了


在编写代码时高兴地流口水

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


任何
构造函数
都会公开一个属性
名称
,即函数名。您可以通过实例(使用
新建
)或
原型
)访问
构造函数

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

从正在运行的函数中获取函数名的简单方法

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

function doSomething() {}

alert(doSomething.name); // alerts "doSomething"
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
Component.prototype.componentWillMount = function componentWillMount() {
    console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}
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;
}
function limbo(){
  for(let i = 0; i < 4; i++){
    console.log(getName(i));
  }
}
function lust(){
  limbo();
}
function gluttony(){
  lust();
}

gluttony();
{your_function}.prototype.constructor.name
if (!(this instanceof arguments.callee)) {
    throw "ReferenceError: " + arguments.callee.name + " is not defined";
}
(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