简体   繁体   English

如何从 function 中获取 function 名称?

[英]How to get the function name from within that function?

How can I access a function name from inside that function?如何从 function 内部访问 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();

In ES6, you can just use myFunction.name .在 ES6 中,你可以只使用myFunction.name

Note: Beware that some JS minifiers might throw away function names , to compress better;注意:注意一些 JS 压缩器可能会丢弃函数名称,以便更好地压缩; you may need to tweak their settings to avoid that.您可能需要调整他们的设置以避免这种情况。

In ES5, the best thing to do is:在 ES5 中,最好的做法是:

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

Using Function.caller is non-standard.使用Function.caller是非标准的。 Function.caller and arguments.callee are both forbidden in strict mode. Function.callerarguments.callee在严格模式下都是被禁止的。

Edit: nus's regex based answer below achieves the same thing, but has better performance!编辑:下面基于 nus 正则表达式的答案实现了相同的目的,但性能更好!

ES6 (inspired by sendy halim's answer below): ES6 (灵感来自sendy halim在下面的回答):

myFunction.name

Explanation on MDN . MDN 上的说明 As of 2015 works in nodejs and all major browsers except IE.截至 2015 年,适用于 nodejs 和除 IE 之外的所有主要浏览器。

Note: On bound functions this will give " bound <originalName> ".注意:在绑定函数上,这将给出“ bound <originalName> ”。 You will have to strip the "bound " if you want to get the original name.如果您想获得原始名称,则必须去除“绑定”。


ES5 (inspired by Vlad's answer): ES5 (受弗拉德的回答启发):

If you have a reference to the function, you can do:如果您有对该函数的引用,则可以执行以下操作:

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
}
  • I have not run unit tests on this, or verified implementation differences, but in principle it should work, if not leave a comment.我没有对此运行单元测试,也没有验证实现差异,但原则上它应该可以工作,如果没有发表评论。
  • Note: won't work on bound functions注意:不适用于绑定函数
  • Note: that caller and callee are considered deprecated.注意: callercallee被视为已弃用。

[1] I include it here because it is legal and often enough syntax highlighting tools fail to take into account the white space between function name and parenthesis. [1]我把它包含在这里是因为它是合法的,而且语法高亮工具通常没有考虑到函数名和括号之间的空格。 On the other hand, I'm not aware of any implementation of .toString() that will include white space here, so that's why you can omit it.另一方面,我不知道 .toString() 的任何实现会在此处包含空格,因此您可以省略它。


As an answer to the original question, I would drop parasitic inheritance and go for some more traditional OOP design patterns.作为对原始问题的回答,我将放弃寄生继承并采用一些更传统的 OOP 设计模式。 I wrote a TidBits.OoJs to comfortably write OOP code in JavaScript with a feature set mimicking C++ (not yet complete, but mostly).我写了一个TidBits.OoJs来舒适地用 JavaScript 编写 OOP 代码,其中包含模仿 C++ 的功能集(尚未完成,但主要是)。

I see from the comments that you would like to avoid passing information parent needs to it's constructor.我从评论中看到您希望避免将parent需要的信息传递给它的构造函数。 I must admit that traditional design patterns won't save you from that one though, since it is generally a considered a good thing to make your dependencies obvious and enforced.我必须承认,传统的设计模式不会让您免于这种情况,因为通常认为使您的依赖项显而易见并强制执行是一件好事。

I would also suggest to steer away from anonymous functions.我还建议避免使用匿名函数。 They only make debugging and profiling a PITA because everything just shows up as "anonymous function", and there is no benefit to them that I'm aware of.他们只对 PITA 进行调试和分析,因为一切都只是显示为“匿名函数”,据我所知,他们没有任何好处。

what you're doing is assigning unnamed function to a variable.您正在做的是将未命名的函数分配给变量。 you probably need named function expression instead ( http://kangax.github.com/nfe/ ).您可能需要命名函数表达式( http://kangax.github.com/nfe/ )。

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

however I'm not sure how much cross-browser that is;但是我不确定那是多少跨浏览器; there's an issue with IE6 that makes you function's name leak to the outer scope. IE6 存在一个问题,使您的函数名称泄漏到外部作用域。 also, arguments.callee is kind of deprecated and will result in error if you're using strict mode .此外,arguments.callee 有点过时,如果您使用strict mode会导致错误。

Any constructor exposes a property name , which is the function name.任何constructor公开一个属性name ,即函数名称。 You access the constructor via an instance (using new ) or a prototype :您可以通过实例(使用new )或prototype访问constructor

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

It looks like the most stupid thing, that I wrote in my life, but it's funny :D这看起来是我一生中写的最愚蠢的事情,但很有趣 :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 - depth of stack. d - 堆栈深度。 0 - return this function name, 1 - parent, etc.; 0 - 返回此函数名称, 1 - 父级等;
[0 + d] - just for understanding - what happens; [0 + d] - 只是为了理解 - 会发生什么;
firefoxMatch - works for safari, but I had really a little time for testing, because mac's owner had returned after smoking, and drove me away :'( firefoxMatch - 适用于 safari,但我真的有一点时间进行测试,因为 mac 的主人在吸烟后回来了,把我赶走了 :'(

Testing:测试:

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

gluttony();

Result:结果:
Chrome:铬合金:
在此处输入图片说明

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

This solution was creating only just for fun !这个解决方案只是为了好玩 Don't use it for real projects.不要将它用于实际项目。 It does not depend on ES specification, it depends only on browser realization.它不依赖于 ES 规范,它只依赖于浏览器实现。 After the next chrome/firefox/safari update it may be broken.在下一次 chrome/firefox/safari 更新后,它可能会损坏。
More than that there is no error (ha) processing - if d will be more than stack length - you will get an error;更重要的是没有错误(ha)处理 - 如果d将超过堆栈长度 - 你会得到一个错误;
For other browsers error's message pattern - you will get an error;对于其他浏览器错误的消息模式 - 你会得到一个错误;
It must work for ES6 classes ( .split('.').pop() ), but you sill can get an error;它必须适用于 ES6 类( .split('.').pop() ),但是你还是会得到一个错误;

This might work for you:这可能对你有用:

function foo() { bar(); }

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

running foo() will output "foo" or undefined if you call from an anonymous function.如果从匿名函数调用,运行 foo() 将输出“foo”或 undefined。

It works with constructors too, in which case it would output the name of the calling constructor (eg "Foo").它也适用于构造函数,在这种情况下,它将输出调用构造函数的名称(例如“Foo”)。

More info here: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller更多信息在这里: https : //developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller

They claim it's non-standard, but also that it's supported by all major browsers: Firefox, Safari, Chrome, Opera and IE.他们声称它是非标准的,但所有主要浏览器都支持它:Firefox、Safari、Chrome、Opera 和 IE。

You can't.你不能。 Functions don't have names according to the standard (though mozilla has such an attribute) - they can only be assigned to variables with names.根据标准,函数没有名称(尽管 mozilla 有这样的属性)——它们只能分配给具有名称的变量。

Also your comment:还有你的评论:

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

is inside the function my.namespace.myFunc.getFn在函数 my.namespace.myFunc.getFn 内

What you can do is return the constructor of an object created by new您可以做的是返回由 new 创建的对象的构造函数

So you could say所以你可以说

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

You could use this, for browsers that support Error.stack (not nearly all, probably)对于支持 Error.stack 的浏览器,您可以使用它(可能不是几乎所有)

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

of course this is for the current function, but you get the idea.当然,这是针对当前功能的,但您明白了。

happy drooling while you code写代码时开心流口水

You can use name property to get the function name, unless you're using an anonymous function您可以使用name属性来获取函数名称,除非您使用匿名函数

For example:例如:

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

now let's try with named function现在让我们尝试命名函数

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

now you can use现在你可以使用

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

You could use Function.name :你可以使用Function.name

In most implementations of JavaScript, once you have your constructor's reference in scope, you can get its string name from its name property (eg Function.name, or Object.constructor.name在 JavaScript 的大多数实现中,一旦在作用域中拥有构造函数的引用,就可以从其 name 属性(例如 Function.name 或 Object.constructor.name )中获取其字符串名称

You could use Function.callee :你可以使用Function.callee

The native arguments.caller method has been deprecated, but most browsers support Function.caller , which will return the actual invoking object (its body of code): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FFunction%2Fcaller本机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

You could create a source map :您可以创建一个源映射

If what you need is the literal function signature (the "name" of it) and not the object itself, you might have to resort to something a little more customized, like creating an array reference of the API string values you'll need to access frequently.如果您需要的是文字函数签名(它的“名称”)而不是对象本身,则您可能不得不求助于一些更自定义的东西,例如创建您需要的 API 字符串值的数组引用频繁访问。 You can map them together using Object.keys() and your array of strings您可以使用Object.keys()和您的字符串数组将它们映射在一起

You can use constructor name like:您可以使用构造函数名称,如:

{your_function}.prototype.constructor.name

this code simply return name of a method.此代码仅返回方法的名称。

as part as ECMAScript 6 you can use Function.name method作为 ECMAScript 6 的一部分,您可以使用Function.name方法

function doSomething() {}

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

I know this is a old question but lately I've been facing some similar issue while trying to decorate some React Component's methods, for debugging purposes.我知道这是一个老问题,但最近我在尝试装饰一些 React 组件的方法以进行调试时遇到了一些类似的问题。 As people already said, arguments.caller and arguments.callee are forbidden in strict mode which is probably enabled by default in your React transpiling.正如人们已经说过的, arguments.callerarguments.callee在严格模式下被禁止,这可能在你的 React 转译中默认启用。 You can either disable it, or I've been able to come up with another hack, because in React all class functions are named, you can actually do this:你可以禁用它,或者我已经能够想出另一个 hack,因为在 React 中所有类函数都被命名,你实际上可以这样做:

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

I had a similar problem and I solved it as follows:我有一个类似的问题,我解决了如下:

Function.prototype.myname = function() {
   return this.toString()
       .substr( 0, this.toString().indexOf( "(" ) )
       .replace( "function ", "" ); 
}

This code implements, in a more comfortable fashion, one response I already read here at the top of this discussion.这段代码以一种更舒适的方式实现了我在本讨论顶部已经阅读过的一个响应。 Now I have a member function retrieving the name of any function object.现在我有一个成员函数来检索任何函数对象的名称。 Here's the full script ...这是完整的脚本......

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

This worked for me.这对我有用。

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

Test code:测试代码:

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

If I understood what you wanted to do, this is what I do inside a function constructor.如果我理解你想做什么,这就是我在函数构造函数中所做的。

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

This will work in ES5, ES6, all browsers and strict mode functions.这将适用于 ES5、ES6、所有浏览器和严格模式功能。

Here's how it looks with a named function.这是使用命名函数的外观。

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

Here's how it looks with an anonymous function.以下是匿名函数的外观。

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

A simple solution to dynamically retrieve function names [like magic variables] is the use of scoped variables.动态检索函数名称(如魔术变量)的一个简单解决方案是使用作用域变量。

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

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

Note: Nested functions cease to be source elements, and are hence not hoisted.注意:嵌套函数不再是源元素,因此不会被提升。 Also, this technique cannot work with anonymous functions.此外,这种技术不能用于匿名函数。

Just try Function.name试试Function.name

const func1 = function() {};

const object = {
  func2: function() {}
};

console.log(func1.name);
// expected output: "func1"

console.log(object.func2.name);
// expected output: "func2"

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

arguments.callee.toString();

seems to be right for your needs.似乎适合您的需求。

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

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

you can use Error.stack to trace the function name and exact position of where you are in it.您可以使用 Error.stack 来跟踪函数名称和您所在位置的确切位置。

See stacktrace.js参见stacktrace.js

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM