Bisakah saya mendapatkan nama fungsi yang sedang berjalan di JavaScript?

185

Apakah mungkin untuk melakukan ini:

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

Saya punya kerangka Dojo dan jQuery di tumpukan saya, jadi jika salah satu dari mereka membuatnya lebih mudah, mereka tersedia.

Sprugman
sumber

Jawaban:

196

Di ES5 dan di atasnya, tidak ada akses ke informasi itu.

Di versi JS yang lebih lama, Anda bisa mendapatkannya dengan menggunakan arguments.callee.

Anda mungkin harus menguraikan nama, karena mungkin akan menyertakan beberapa sampah tambahan. Padahal, dalam beberapa implementasi Anda hanya bisa mendapatkan nama menggunakan arguments.callee.name.

Parsing:

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

   alert(myName);
}

Sumber: Javascript - dapatkan nama fungsi saat ini .

Mat
sumber
Sebenarnya, sebenarnya lebih memperhatikan pertanyaan Anda, sepertinya Anda mungkin ingin sampah ekstra :)
Matt
23
@ Andrew - Anda benar, saya seharusnya mengatakan itu. Itu adalah salinan / tempel / pembersihan cepat dari sesuatu yang sudah saya bookmark, dan pengawasan pada bagian saya. Terima kasih telah menambahkannya ke posting saya.
Matt
81
Istirahat dalam mode ketat ES5.
Raynos
4
Oh ... itu sebabnya orang selalu mengalahkan saya pada kecepatan untuk membalas. Saya tidak memikirkan itu.
Erik Reppen
9
jika Anda menggunakan objek literal untuk metode Anda dan tidak ada nama metode aktual, maka ini tidak akan berfungsi sebagai arguments.callee bertindak seperti fungsi anonim yang tidak akan membawa nama fungsi apa pun. Anda harus memastikan bahwa Anda menambahkan nama fungsi itu dua kali. Lihatlah contoh jsfiddle ini: jsfiddle.net/ncays . masalah lain dengan ini, arguments.calleeadalah tidak diperbolehkan dalam mode ketat.
hellatan
75

Untuk fungsi non-anonim

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

Tetapi dalam kasus penangan kesalahan hasilnya adalah nama fungsi penangan kesalahan, bukan?

fforw
sumber
2
Bekerja sangat baik di Chrome. Jauh lebih baik daripada jawaban yang diterima.
B Seven
1
Patut diingat: eslint.org/docs/rules/no-caller > "usang dalam versi JavaScript yang akan datang dan penggunaannya dilarang dalam ECMAScript 5 saat dalam mode ketat."
Jeremy
44

Semua yang Anda butuhkan sederhana. Buat fungsi:

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

Setelah itu kapan pun Anda butuhkan, Anda cukup menggunakan:

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

foo() 
// Logs: "foo"
Igor Ostroumov
sumber
3
Terima kasih, ini jauh lebih elegan daripada mengurai string.
modle13
1
Tampaknya itu jawaban terbaik!
Sergey
Sempurna. Saat itulah JS tidak memiliki konstanta asli seperti PHP dengan konstanta Magic ...
stamster
Chrome memberi saya kesalahan ketik karena properti 'nama' tidak ada di pemanggil. Namun, inspeksi mengungkapkan bahwa ini berhasil:function getFuncName() { return getFuncName.name }
Tom Anderson
@ TomAnderson dengan kembalian Anda, Anda sekarang mendapatkan nama getFuncNamedaripada nama pemanggilnya.
Mark McKenna
30

Menurut MDN

Peringatan: ECMAScript (ES5) edisi ke-5 melarang penggunaan arguments.callee () dalam mode ketat. Hindari menggunakan arguments.callee () dengan memberikan ekspresi fungsi nama atau menggunakan deklarasi fungsi di mana fungsi harus memanggil dirinya sendiri.

Sebagaimana dicatat ini berlaku hanya jika skrip Anda menggunakan "mode ketat". Ini terutama karena alasan keamanan dan sayangnya saat ini tidak ada alternatif untuk ini.

Laimis
sumber
21

Ini harus dilakukan:

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

Untuk penelepon, gunakan saja caller.toString().

Andy E
sumber
8
Ini bekerja untuk saya tapi saya pikir ada kesalahan ketik pada regexp Anda. Saya harus mengambil backslash sebelum[
declan
4
@ deklan: ya, Anda benar. Mengejutkan bahwa tidak ada orang lain yang menunjukkan bahwa dalam hampir 3 tahun jawaban ini ada di sini :-)
Andy E
@AndyE mungkin tidak ada yang menunjukkannya karena begitu kita melihat regexp, kita memasuki TL; mode DR dan mencari jawaban lain;)
BitTickler
11

Ini harus masuk dalam kategori "peretasan terjelek di dunia", tapi begini saja.

Pertama-tama, mencetak nama fungsi saat ini (seperti pada jawaban lain) tampaknya memiliki penggunaan terbatas bagi saya, karena Anda semacam sudah tahu apa fungsinya!

Namun, mengetahui nama fungsi panggilan bisa sangat berguna untuk fungsi penelusuran. Ini dengan regexp, tetapi menggunakan indexOf sekitar 3x lebih cepat:

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

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

me();
James Hugard
sumber
solusi keren, tetapi FYI Function # caller adalah non-standar developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Max Heiber
Mengetahui nama fungsi saat ini dapat menjadi sangat penting jika fungsi tersebut dibuat secara dinamis dari database dan membutuhkan informasi konteks di dalam fungsi yang dikunci untuk nama fungsi.
Paul Chernoch
9

Inilah cara yang akan berhasil:

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

Kemudian dalam tes Anda:

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

});

Perhatikan bahwa tes ketiga hanya akan berfungsi jika tes terletak di / util / functions

Anthony
sumber
7

The getMyNamefungsi dalam potongan bawah kembali nama fungsi menelepon. Ini hack dan bergantung pada non-standar fitur: Error.prototype.stack. Perhatikan bahwa format string yang dikembalikan oleh Error.prototype.stackdiimplementasikan secara berbeda di mesin yang berbeda, jadi ini mungkin tidak akan berfungsi di mana-mana:

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

Tentang solusi lain: arguments.callee tidak diperbolehkan dalam mode ketat dan Function.prototype.callermerupakan non-standar dan tidak diperbolehkan dalam mode ketat .

Max Heiber
sumber
memperluas ini untuk juga menunjukkan posisi dalam fungsi dan mendukung fungsi anonim dengan: .replace (/ ^ \ s + at \ s (. +?) (?: \ s. *: |:) (. *?): (. * ?))? $ / g, '$ 1 ($ 2: $ 3)')
kofifus
Function.prototype.caller juga tidak diizinkan dalam mode ketat.
fijiaaron
1
Berfungsi sempurna bahkan untuk fungsi panah, jawaban yang diremehkan
Hao Wu
3

Kasing penggunaan lain bisa berupa acara dispatcher yang terikat saat runtime:

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

Keuntungannya di sini adalah operator dapat dengan mudah digunakan kembali dan tidak harus menerima antrian pengiriman sebagai argumen, alih-alih itu tersirat dengan nama doa ...

Pada akhirnya, kasus umum yang disajikan di sini adalah "menggunakan nama fungsi sebagai argumen sehingga Anda tidak harus meneruskannya secara eksplisit", dan itu bisa berguna dalam banyak kasus, seperti jquery animate () callback opsional, atau dalam callback timeout / interval, (yaitu Anda hanya melewati NAMA funcion).

Sampiolin
sumber
2

Nama fungsi saat ini dan bagaimana hal itu dapat diperoleh tampaknya telah berubah selama 10 tahun terakhir, sejak pertanyaan ini diajukan.

Sekarang, bukan menjadi pengembang web pro yang tahu tentang semua sejarah semua browser yang pernah ada, di sini adalah cara kerjanya untuk saya di browser chrome 2019:

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

Beberapa jawaban lain mengalami beberapa kesalahan chrome tentang kode javascript yang ketat dan yang lainnya.

BitTickler
sumber
1

Karena Anda telah menulis fungsi bernama foodan Anda tahu itu myfile.jsmengapa Anda perlu mendapatkan informasi ini secara dinamis?

Bahwa menjadi kata Anda dapat menggunakan arguments.callee.toString()di dalam fungsi (ini adalah representasi string dari seluruh fungsi) dan regex nilai dari nama fungsi.

Berikut adalah fungsi yang akan memunculkan namanya sendiri:

function foo() {
    re = /^function\s+([^(]+)/
    alert(re.exec(arguments.callee.toString())[1]);             
}
Andrew Hare
sumber
5
Saya sedang mengerjakan penangan kesalahan, dan saya ingin melaporkan fungsi panggilan.
sprugman
1

Kombinasi dari beberapa tanggapan yang saya lihat di sini. (Diuji dalam 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);
}

Memanggil randomFunction () akan mengingatkan string yang berisi nama fungsi.

Demo JS Fiddle: http://jsfiddle.net/mjgqfhbe/

buddamus
sumber
1

Informasi aktual pada tahun 2016 tahun.


Hasil untuk deklarasi fungsi

Hasil di Opera

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

Menghasilkan 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

Menghasilkan 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

Tidak berfungsi di Firefox. Belum diuji pada IE dan Edge.


Hasil untuk ekspresi fungsi

Menghasilkan NodeJS

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

Menghasilkan Chrome

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

Tidak berfungsi di Firefox, Opera. Belum diuji pada IE dan Edge.

Catatan:

  1. Fungsi anonim tidak masuk akal untuk memeriksa.
  2. Lingkungan pengujian

~ $ 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
PADYMKO
sumber
1
(function f() {
    console.log(f.name);  //logs f
})();

Variasi naskah:

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

f2(f1);  //Logs f1

Catatan hanya tersedia di mesin yang sesuai dengan ES6 / ES2015. Untuk lebih banyak lihat

Ole
sumber
0

Ini satu liner:

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

Seperti ini:

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

Ini varian dari jawaban Igor Ostroumov :

Jika Anda ingin menggunakannya sebagai nilai default untuk suatu parameter, Anda perlu mempertimbangkan panggilan tingkat kedua ke 'pemanggil':

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

Ini secara dinamis akan memungkinkan implementasi yang dapat digunakan kembali dalam berbagai fungsi.

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

function bar(myFunctionName = getFunctionsNameThatCalledThisFunction())
{ 
  alert(myFunctionName);
}

// pops-up "foo"
function foo()
{
  bar();
}

function crow()
{
  bar();
}

foo();
crow();

Jika Anda ingin nama file juga, berikut adalah solusi menggunakan jawaban dari F-3000 pada pertanyaan lain:

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();
}
SMAG
sumber
-1

Mencoba:

alert(arguments.callee.toString());
Deniz Dogan
sumber
3
Itu akan mengembalikan seluruh fungsi sebagai string
Andy E
-7

Jawabannya singkat: alert(arguments.callee.name);

Kemangi
sumber
12
"nom" adalah "nama" dalam bahasa Prancis. Apakah detail seperti ini berubah di antara versi bahasa browser? Saya tidak akan berpikir begitu.
argyle