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.

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 .


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?


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"

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.


21

Ini harus dilakukan:

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

Untuk penelepon, gunakan saja caller.toString().


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

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


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 .


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


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.


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

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/



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

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


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

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

-1

Mencoba:

alert(arguments.callee.toString());

3
Itu akan mengembalikan seluruh fungsi sebagai string
Andy E

-7

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


12
"nom" adalah "nama" dalam bahasa Prancis. Apakah detail seperti ini berubah di antara versi bahasa browser? Saya tidak akan berpikir begitu.
argyle
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.