ฉันจะได้รับชื่อฟังก์ชั่นที่กำลังทำงานอยู่ในจาวาสคริปต์ได้หรือไม่?


185

เป็นไปได้ที่จะทำสิ่งนี้:

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

ฉันมีกรอบ Dojo และ jQuery ในสแต็กของฉันดังนั้นหากหนึ่งในนั้นทำให้ง่ายขึ้น

คำตอบ:


196

ใน 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 - ได้รับชื่อของฟังก์ชั่นในปัจจุบัน


จริงจริงให้ความสนใจมากขึ้นในคำถามของคุณดูเหมือนคุณอาจต้องการขยะพิเศษ :)
แมตต์

23
@ แอนดรูว์ - คุณพูดถูกฉันควรจะบอกว่า มันเป็นการคัดลอก / วาง / ล้างอย่างรวดเร็วของบางสิ่งที่ฉันทำบุ๊กมาร์กไว้แล้วและการกำกับดูแลในส่วนของฉัน ขอบคุณสำหรับการเพิ่มลงในโพสต์ของฉัน
Matt

81
หยุดพักในโหมดเข้มงวด ES5
Raynos

4
โอ้ ... นั่นเป็นเหตุผลที่ผู้คนมักจะเอาชนะฉันด้วยความเร็วที่จะตอบกลับ ฉันไม่ได้คิดอย่างนั้น
Erik Reppen

9
หากคุณใช้วัตถุตามตัวอักษรสำหรับวิธีการของคุณและไม่มีชื่อวิธีการที่แท้จริงแล้วสิ่งนี้จะไม่ทำงานในขณะที่ arguments.callee ทำหน้าที่เหมือนฟังก์ชันที่ไม่ระบุชื่อซึ่งจะไม่ใช้ชื่อฟังก์ชันใด ๆ คุณจะต้องตรวจสอบให้แน่ใจว่าคุณได้เพิ่มชื่อฟังก์ชันนั้นสองครั้ง ลองดูตัวอย่าง jsfiddle นี้: jsfiddle.net/ncays อย่างไรก็ตามปัญหาอื่นของสิ่งนี้arguments.calleeคือไม่ได้รับอนุญาตภายใต้โหมดเข้มงวด
hellatan

75

สำหรับฟังก์ชั่นที่ไม่ระบุชื่อ

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

แต่ในกรณีที่ตัวจัดการข้อผิดพลาดผลลัพธ์จะเป็นชื่อของฟังก์ชันตัวจัดการข้อผิดพลาดใช่ไหม


2
ใช้งานได้ดีใน Chrome ดีกว่าคำตอบที่ได้รับการยอมรับ
B เซเว่น

1
ควรจำไว้ว่า: eslint.org/docs/rules/no-caller > "เลิกใช้จาวาสคริปต์ในเวอร์ชันอนาคตและห้ามมิให้ใช้งานใน ECMAScript 5 ในขณะที่อยู่ในโหมดเข้มงวด"
Jeremy

44

ทุกสิ่งที่คุณต้องการนั้นง่าย สร้างฟังก์ชั่น:

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

หลังจากนั้นเมื่อใดก็ตามที่คุณต้องการคุณเพียงแค่ใช้:

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

foo() 
// Logs: "foo"

3
ขอบคุณนี่คือความงดงามมากกว่าการแยกสตริง
mod1313

1
ดูเหมือนว่าจะเป็นคำตอบที่ดีที่สุด!
Sergey

สมบูรณ์ นั่นคือเมื่อ JS ไม่ได้มีค่าคงที่พื้นเมืองเช่น PHP จะมีค่าคงที่เมจิก ...
stamster

Chrome ทำให้ฉันมีข้อผิดพลาดประเภทเนื่องจากคุณสมบัติ 'ชื่อ' ไม่มีอยู่ในผู้โทร อย่างไรก็ตามการตรวจสอบพบว่าสิ่งนี้ได้ผล:function getFuncName() { return getFuncName.name }
Tom Anderson

@ TomAnderson พร้อมการเปลี่ยนแปลงของคุณตอนนี้คุณได้รับชื่อgetFuncNameแทนที่จะเป็นชื่อของผู้โทร
Mark McKenna

30

ตามMDN

คำเตือน: ECMAScript (ES5) รุ่นที่ 5 ห้ามมิให้มีการใช้ arguments.callee () ในโหมดเข้มงวด หลีกเลี่ยงการใช้ arguments.callee () โดยให้ชื่อฟังก์ชันแก่นิพจน์หรือใช้ฟังก์ชันประกาศที่ฟังก์ชันต้องเรียกใช้ฟังก์ชันเอง

ตามที่ระบุไว้สิ่งนี้จะใช้เฉพาะในกรณีที่สคริปต์ของคุณใช้ "โหมดเข้มงวด" นี่คือเหตุผลด้านความปลอดภัยเป็นหลักและในปัจจุบันน่าเศร้าที่ไม่มีทางเลือกสำหรับสิ่งนี้


21

สิ่งนี้ควรทำ:

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

caller.toString()สำหรับผูที่ใช้เพียง


8
สิ่งนี้ใช้ได้สำหรับฉัน แต่ฉันคิดว่ามีความผิดพลาดใน regexp ของคุณ ฉันต้องถอดแบ็กสแลชออกก่อน[
ปฏิเสธ

4
@declan: ใช่คุณพูดถูก มันน่าแปลกใจที่ไม่มีใครอื่นชี้ให้เห็นว่าในรอบเกือบ 3 ปีคำตอบนี้อยู่ที่นี่ :-)
Andy E

@AndyE อาจไม่มีใครชี้ให้เห็นเพราะเมื่อเราเห็น regexp เราก็เข้าสู่โหมด TL; DR และค้นหาคำตอบอื่น ๆ ;)
24914

11

สิ่งนี้จะต้องอยู่ในหมวดหมู่ของ "แฮ็กที่น่าเกลียดที่สุดในโลก" แต่ที่นี่คุณไป

ก่อนอื่นการพิมพ์ชื่อของฟังก์ชั่นปัจจุบัน (เหมือนในคำตอบอื่น ๆ ) ดูเหมือนว่าจะมีการใช้งานที่ จำกัด กับฉันเนื่องจากคุณรู้อยู่แล้วว่าฟังก์ชั่นนี้คืออะไร!

อย่างไรก็ตามการค้นหาชื่อของฟังก์ชันการเรียกอาจเป็นประโยชน์สำหรับฟังก์ชันติดตาม นี่เป็น regexp แต่การใช้ 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();

วิธีแก้ปัญหาที่ยอดเยี่ยม แต่ฟังก์ชั่น FYI # ผู้โทรนั้นไม่ได้เป็นมาตรฐานdeveloper.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Max Heiber

การรู้ชื่อของฟังก์ชั่นปัจจุบันอาจมีความสำคัญหากฟังก์ชั่นนั้นถูกสร้างขึ้นแบบไดนามิกจากฐานข้อมูลและต้องการข้อมูลบริบทภายในฟังก์ชั่นที่คีย์ไปที่ชื่อฟังก์ชั่น
Paul Chernoch

9

นี่คือวิธีที่ใช้งานได้:

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 / ฟังก์ชั่น


7

getMyNameฟังก์ชั่นในตัวอย่างด้านล่างผลตอบแทนที่ชื่อของฟังก์ชั่นการโทร มันสับและอาศัยอยู่กับที่ไม่ได้มาตรฐาน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เป็นที่ไม่ได้มาตรฐานและไม่ได้รับอนุญาตในโหมดที่เข้มงวด


ขยายสิ่งนี้เพื่อแสดงตำแหน่งในฟังก์ชั่นและรองรับฟังก์ชั่นที่ไม่ระบุชื่อด้วย: .replace (/ ^ \ s + ที่ \ s (. +?) (?: \ s. *: |:) (. *?): (. * ?))? $ / g, '$ 1 ($ 2: $ 3)')
kofifus

Function.prototype.caller ไม่อนุญาตในโหมดเข้มงวด
fijiaaron

1
ทำงานได้สมบูรณ์แบบแม้สำหรับฟังก์ชั่นลูกศร
Hao Wu

3

กรณีการใช้งานอื่นอาจเป็นตัวส่งเหตุการณ์ที่ถูกผูกไว้ที่รันไทม์:

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 () ตัวเลือกการโทรกลับ หรือในการโทรกลับหมดเวลา / ช่วงเวลา (เช่นคุณผ่าน funcion NAME เท่านั้น)


2

ชื่อของฟังก์ชั่นปัจจุบันและวิธีการรับสามารถดูเหมือนจะมีการเปลี่ยนแปลงในช่วง 10 ปีที่ผ่านมาเนื่องจากคำถามนี้ถูกถาม

ตอนนี้ไม่ได้เป็นนักพัฒนาเว็บมืออาชีพที่รู้ประวัติของเบราว์เซอร์ทั้งหมดที่เคยมีอยู่นี่คือวิธีที่มันใช้ได้กับฉันในเบราว์เซอร์ chrome 2019:

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

คำตอบอื่น ๆ บางข้อพบข้อผิดพลาดของ Chrome เกี่ยวกับรหัสจาวาสคริปต์ที่เข้มงวดและอะไรก็ตาม


1

เมื่อคุณเขียนฟังก์ชั่นชื่อfooและคุณรู้ว่ามันเป็นmyfile.jsเพราะเหตุใดคุณจึงจำเป็นต้องได้รับข้อมูลนี้แบบไดนามิก?

ที่กล่าวว่าคุณสามารถใช้arguments.callee.toString()ภายในฟังก์ชั่น (นี่คือการเป็นตัวแทนสตริงของฟังก์ชั่นทั้งหมด) และ regex ออกค่าของชื่อฟังก์ชั่น

นี่คือฟังก์ชั่นที่จะแยกชื่อของตัวเองออกมา:

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

5
ฉันกำลังทำงานกับตัวจัดการข้อผิดพลาดและฉันต้องการรายงานฟังก์ชั่นการโทร
sprugman

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 Fiddle: http://jsfiddle.net/mjgqfhbe/



1

ข้อมูลเป็นจริงในปี 2559


ผลลัพธ์สำหรับการประกาศฟังก์ชัน

ส่งผลให้ 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

ส่งผลให้ 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

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

รูปแบบตัวพิมพ์:

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

f2(f1);  //Logs f1

หมายเหตุมีเฉพาะในเอ็นจิ้นที่สอดคล้องกับ ES6 / ES2015 ดูเพิ่มเติม


0

นี่คือหนึ่งซับ:

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

0

นี่คือตัวแปรของIgor Ostroumov'sคำตอบที่คำตอบ :

หากคุณต้องการใช้เป็นค่าเริ่มต้นสำหรับพารามิเตอร์คุณต้องพิจารณาการเรียกระดับที่สองเป็น 'ผู้โทร':

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


-7

คำตอบสั้น ๆ : alert(arguments.callee.name);


12
"nom" คือ "name" ในภาษาฝรั่งเศส รายละเอียดประเภทนี้เปลี่ยนแปลงระหว่างเบราว์เซอร์เวอร์ชันภาษาหรือไม่ ฉันจะไม่คิดอย่างนั้น
argyle
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.