簡體   English   中英

我可以在 JavaScript 中獲取當前正在運行的函數的名稱嗎?

[英]Can I get the name of the currently running function in JavaScript?

是否有可能做到這一點:

myfile.js:
function foo() {
    alert(<my-function-name>);
    // pops-up "foo"
    // or even better: "myfile.js : foo"
}

我的堆棧中有 Dojo 和 jQuery 框架,所以如果其中任何一個更容易,它們都是可用的。

在 ES5 及更高版本中,無法訪問該信息。

在舊版本的 JS 中,您可以使用arguments.callee來獲取它。

不過,您可能需要解析該名稱,因為它可能包含一些額外的垃圾。 不過,在某些實現中,您可以簡單地使用arguments.callee.name獲取名稱。

解析:

function DisplayMyName() 
{
   var myName = arguments.callee.toString();
   myName = myName.substr('function '.length);
   myName = myName.substr(0, myName.indexOf('('));

   alert(myName);
}

來源: Javascript - 獲取當前函數名稱

對於非匿名函數

function foo()
{ 
    alert(arguments.callee.name)
}

但是在錯誤處理程序的情況下,結果將是錯誤處理程序函數的名稱,不是嗎?

您需要的一切都很簡單。 創建函數:

function getFuncName() {
   return getFuncName.caller.name
}

之后,無論何時需要,您只需使用:

function foo() { 
  console.log(getFuncName())
}

foo() 
// Logs: "foo"

根據MDN

警告: ECMAScript (ES5) 第 5 版禁止在嚴格模式下使用 arguments.callee()。 避免使用arguments.callee() 通過給函數表達式一個名稱或在函數必須調用自身的地方使用函數聲明。

如上所述,這適用,如果你的腳本使用“嚴格模式”。 這主要是出於安全原因,遺憾的是目前沒有其他選擇。

這應該這樣做:

var fn = arguments.callee.toString().match(/function\s+([^\s\(]+)/);
alert(fn[1]);

對於調用者,只需使用caller.toString()

下面代碼片段中的getMyName函數返回調用函數的名稱。 這是一個 hack 並且依賴於非標准特性: Error.prototype.stack 請注意, Error.prototype.stack返回的字符串格式在不同引擎中的實現方式不同,因此這可能不適用於所有地方:

 function getMyName() { var e = new Error('dummy'); var stack = e.stack .split('\\n')[2] // " at functionName ( ..." => "functionName" .replace(/^\\s+at\\s+(.+?)\\s.+/g, '$1' ); return stack } function foo(){ return getMyName() } function bar() { return foo() } console.log(bar())

關於其他解決方案: arguments.callee 在嚴格模式下是不允許的,Function.prototype.caller非標准的,在嚴格模式下是不允許的

這是一種有效的方法:

export function getFunctionCallerName (){
  // gets the text between whitespace for second part of stacktrace
  return (new Error()).stack.match(/at (\S+)/g)[1].slice(3);
}

然后在你的測試中:

import { expect } from 'chai';
import { getFunctionCallerName } from '../../../lib/util/functions';

describe('Testing caller name', () => {

    it('should return the name of the function', () => {
      function getThisName(){
        return getFunctionCallerName();
      }

      const functionName = getThisName();

      expect(functionName).to.equal('getThisName');
    });

  it('should work with an anonymous function', () => {


    const anonymousFn = function (){
      return getFunctionCallerName();
    };

    const functionName = anonymousFn();

    expect(functionName).to.equal('anonymousFn');
  });

  it('should work with an anonymous function', () => {
    const fnName = (function (){
      return getFunctionCallerName();
    })();

    expect(/\/util\/functions\.js/.test(fnName)).to.eql(true);
  });

});

請注意,第三個測試僅在測試位於 /util/functions 時才有效

這必須歸入“世界上最丑陋的黑客”類別,但在這里。

首先,打印當前函數的名稱(如在其他答案中)似乎對我的用處有限,因為您已經知道該函數是什么!

但是,找出調用函數的名稱對於跟蹤函數可能非常有用。 這是使用正則表達式,但使用 indexOf 會快 3 倍:

function getFunctionName() {
    var re = /function (.*?)\(/
    var s = getFunctionName.caller.toString();
    var m = re.exec( s )
    return m[1];
}

function me() {
    console.log( getFunctionName() );
}

me();

自從提出這個問題以來,當前函數的名稱及其獲取方式在過去 10 年中似乎發生了變化。

現在,我不是一個了解所有瀏覽器歷史的專業 Web 開發人員,以下是它在 2019 年 chrome 瀏覽器中的工作原理:

function callerName() {
    return callerName.caller.name;
}
function foo() {
    let myname = callerName();
    // do something with it...
}

其他一些答案遇到了一些關於嚴格的 javascript 代碼和諸如此類的 chrome 錯誤。

另一個用例可能是在運行時綁定的事件調度程序:

MyClass = function () {
  this.events = {};

  // Fire up an event (most probably from inside an instance method)
  this.OnFirstRun();

  // Fire up other event (most probably from inside an instance method)
  this.OnLastRun();

}

MyClass.prototype.dispatchEvents = function () {
  var EventStack=this.events[GetFunctionName()], i=EventStack.length-1;

  do EventStack[i]();
  while (i--);
}

MyClass.prototype.setEvent = function (event, callback) {
  this.events[event] = [];
  this.events[event].push(callback);
  this["On"+event] = this.dispatchEvents;
}

MyObject = new MyClass();
MyObject.setEvent ("FirstRun", somecallback);
MyObject.setEvent ("FirstRun", someothercallback);
MyObject.setEvent ("LastRun", yetanothercallback);

這里的優點是調度器可以很容易地重用,並且不必將調度隊列作為參數接收,而是隱含地帶有調用名稱......

最后,這里介紹的一般情況是“使用函數名稱作為參數,因此您不必顯式傳遞它”,這在許多情況下可能很有用,例如 jquery animate() 可選回調,或者在超時/間隔回調中,(即你只傳遞一個函數名稱)。

(function f() {
    console.log(f.name);  //logs f
})();

打字稿變體:

function f1() {} 
function f2(f:Function) {
   console.log(f.name);
}

f2(f1);  //Logs f1

注意僅在符合 ES6/ES2015 的引擎中可用。 更多信息請參見

既然您已經編寫了一個名為foo的函數並且您知道它在myfile.js為什么您需要動態獲取此信息?

話雖如此,您可以在函數內部使用arguments.callee.toString() (這是整個函數的字符串表示)並正則表達式輸出函數名稱的值。

這是一個會吐出自己名字的函數:

function foo() {
    re = /^function\s+([^(]+)/
    alert(re.exec(arguments.callee.toString())[1]);             
}

我在這里看到的幾個回復的組合。 (在 FF、Chrome、IE11 中測試)

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

function randomFunction(){
    var proof = "This proves that I found the name '" + functionName() + "'";
    alert(proof);
}

調用 randomFunction() 將警告包含函數名稱的字符串。

JS小提琴演示: http : //jsfiddle.net/mjgqfhbe/

可以在此答案中找到對此的更新答案: https : //stackoverflow.com/a/2161470/632495

並且,如果您不想點擊:

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

信息以2016年的實際為准。


函數聲明的結果

歌劇中的結果

>>> (function func11 (){
...     console.log(
...         'Function name:',
...         arguments.callee.toString().match(/function\s+([_\w]+)/)[1])
... })();
... 
... (function func12 (){
...     console.log('Function name:', arguments.callee.name)
... })();
Function name:, func11
Function name:, func12

結果在 Chrome

(function func11 (){
    console.log(
        'Function name:',
        arguments.callee.toString().match(/function\s+([_\w]+)/)[1])
})();

(function func12 (){
    console.log('Function name:', arguments.callee.name)
})();
Function name: func11
Function name: func12

在 NodeJS 中的結果

> (function func11 (){
...     console.log(
.....         'Function name:',
.....         arguments.callee.toString().match(/function\s+([_\w]+)/)[1])
... })();
Function name: func11
undefined
> (function func12 (){
...     console.log('Function name:', arguments.callee.name)
... })();
Function name: func12

在 Firefox 中不起作用。 未在 IE 和 Edge 上測試。


函數表達式的結果

在 NodeJS 中的結果

> var func11 = function(){
...     console.log('Function name:', arguments.callee.name)
... }; func11();
Function name: func11

結果在 Chrome

var func11 = function(){
    console.log('Function name:', arguments.callee.name)
}; func11();
Function name: func11

不適用於 Firefox、Opera。 未在 IE 和 Edge 上測試。

筆記:

  1. 匿名函數檢查沒有意義。
  2. 測試環境

~ $ google-chrome --version
Google Chrome 53.0.2785.116           
~ $ opera --version
Opera 12.16 Build 1860 for Linux x86_64.
~ $ firefox --version
Mozilla Firefox 49.0
~ $ node
node    nodejs  
~ $ nodejs --version
v6.8.1
~ $ uname -a
Linux wlysenko-Aspire 3.13.0-37-generic #64-Ubuntu SMP Mon Sep 22 21:28:38 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

這是一個單班輪:

    arguments.callee.toString().split('\n')[0].substr('function '.length).replace(/\(.*/, "").replace('\r', '')

像這樣:

    function logChanges() {
      let whoami = arguments.callee.toString().split('\n')[0].substr('function '.length).replace(/\(.*/, "").replace('\r', '');
      console.log(whoami + ': just getting started.');
    }

這是Igor Ostroumov答案的變體:

如果您想將其用作參數的默認值,則需要考慮對“caller”進行二級調用:

function getFunctionsNameThatCalledThisFunction()
{
  return getFunctionsNameThatCalledThisFunction.caller.caller.name;
}

這將動態地允許在多個功能中實現可重用。

 function getFunctionsNameThatCalledThisFunction() { return getFunctionsNameThatCalledThisFunction.caller.caller.name; } function bar(myFunctionName = getFunctionsNameThatCalledThisFunction()) { alert(myFunctionName); } // pops-up "foo" function foo() { bar(); } function crow() { bar(); } foo(); crow();

如果您也需要文件名,這里是使用F-3000對另一個問題的回答的解決方案:

function getCurrentFileName()
{
  let currentFilePath = document.scripts[document.scripts.length-1].src 
  let fileName = currentFilePath.split('/').pop() // formatted to the OP's preference

  return fileName 
}

function bar(fileName = getCurrentFileName(),  myFunctionName = getFunctionsNameThatCalledThisFunction())
{
  alert(fileName + ' : ' + myFunctionName);
}

// or even better: "myfile.js : foo"
function foo()
{
  bar();
}

由於 arguments.callee.name 是非標准的,並且在 ECMAScript 5 嚴格模式中被禁止( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/callee ),一個簡單的動態檢索函數名稱 [如魔術變量] 的解決方案是使用作用域變量和 Function.name 屬性。

{
  function foo() {
    alert (a.name);
  }; let a = foo
}
{
  function foo2() {
    alert(a.name)
  }; let a = foo2
};
foo();//logs foo
foo2();//logs foo2

注意:嵌套函數不再是源元素,因此不會被提升。 此外,這種技術不能用於匿名函數。

arguments 對象是所有非箭頭函數中可用的局部變量。
您可以通過使用其參數對象來引用該函數內部的函數參數。
它對調用函數的每個參數都有條目,第一個條目的索引為 0。

所以你基本上可以使用arguments.callee.name但在這樣的命名函數中:

function i_have_a_name() {
    console.log(`My name is:`, arguments.callee.name)
}
> i_have_a_name()
My name is: i_have_a_name

不幸的是,它在箭頭函數中不可用:

const i_have_a_name = () => {
    console.log(`My name is:`, arguments.callee.name)
}
> i_have_a_name()
Uncaught ReferenceError: arguments is not defined
    at i_have_a_name (REPL3:2:32)

來源: https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments

嘗試:

alert(arguments.callee.toString());

答案很簡單: alert(arguments.callee.name);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM