Tôi có thể lấy tên của hàm hiện đang chạy trong JavaScript không?


182

Có khả năng làm cái này không:

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

Tôi đã có các khung Dojo và jQuery trong ngăn xếp của mình, vì vậy nếu một trong hai khung đó làm cho nó dễ dàng hơn, chúng có sẵn.

Câu trả lời:


196

Trong ES5 trở lên, không có quyền truy cập vào thông tin đó.

Trong các phiên bản cũ hơn của JS, bạn có thể lấy nó bằng cách sử dụng arguments.callee.

Bạn có thể phải phân tích tên, mặc dù nó có thể sẽ bao gồm một số rác bổ sung. Mặc dù, trong một số triển khai, bạn chỉ cần lấy tên bằng cách sử dụng arguments.callee.name.

Phân tích cú pháp:

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

   alert(myName);
}

Nguồn: Javascript - lấy tên hàm hiện tại .


Trên thực tế, thực sự chú ý nhiều hơn đến câu hỏi của bạn, có vẻ như bạn có thể muốn thêm rác :)
Matt

23
@Andrew - Bạn nói đúng, tôi nên nói rằng. Đó là một bản sao nhanh chóng / dán / dọn dẹp thứ gì đó tôi đã đánh dấu và phần giám sát của tôi. Cảm ơn bạn đã thêm nó vào bài viết của tôi.
Matt

80
Phá vỡ trong chế độ nghiêm ngặt ES5.
Raynos

4
Ồ ... đó là lý do tại sao mọi người luôn đánh tôi với tốc độ để trả lời. Tôi đã không nghĩ về điều đó.
Erik Reppen

9
nếu bạn đang sử dụng một đối tượng bằng chữ cho các phương thức của mình và không có tên phương thức thực tế, thì điều này sẽ không hoạt động như argument.callee hoạt động như một hàm ẩn danh sẽ không mang bất kỳ tên hàm nào. Bạn sẽ phải đảm bảo bạn thêm tên hàm đó hai lần. Hãy xem ví dụ jsfiddle này: jsfiddle.net/ncays . Tuy nhiên, một vấn đề khác với điều này arguments.calleelà không được phép trong chế độ nghiêm ngặt.
hellatan

75

Đối với các chức năng không ẩn danh

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

Nhưng trong trường hợp trình xử lý lỗi, kết quả sẽ là tên của hàm xử lý lỗi, phải không?


2
Hoạt động tuyệt vời trong Chrome. Tốt hơn nhiều so với câu trả lời được chấp nhận.
B Bảy

Đáng ghi nhớ: eslint.org/docs/rules/no-caller > "không dùng nữa trong các phiên bản JavaScript trong tương lai và việc sử dụng chúng bị cấm trong ECMAScript 5 khi ở chế độ nghiêm ngặt."
Jeremy

44

Tất cả những gì bạn cần là đơn giản. Tạo chức năng:

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

Sau đó, bất cứ khi nào bạn cần, bạn chỉ cần sử dụng:

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

foo() 
// Logs: "foo"

3
Cảm ơn, điều này là thanh lịch hơn nhiều so với phân tích một chuỗi.
modle13

1
Nó dường như là câu trả lời tốt nhất!
Serge

Hoàn hảo. Đó là khi JS không có các hằng số nguyên gốc như PHP làm với các hằng số Magic ...
stamster

Chrome cho tôi một lỗi loại vì 'tên' thuộc tính không tồn tại trên người gọi. Tuy nhiên, kiểm tra cho thấy rằng điều này đã làm việc:function getFuncName() { return getFuncName.name }
Tom Anderson

@TomAnderson với sự thay đổi của bạn, giờ bạn đã nhận được tên của getFuncNamechứ không phải tên của người gọi nó.
Đánh dấu McKenna

30

Theo MDN

Cảnh báo: Phiên bản thứ 5 của ECMAScript (ES5) cấm sử dụng argument.callee () trong chế độ nghiêm ngặt. Tránh sử dụng argument.callee () bằng cách đặt tên biểu thức hàm hoặc sử dụng khai báo hàm trong đó hàm phải gọi chính nó.

Như đã lưu ý, điều này chỉ áp dụng nếu tập lệnh của bạn sử dụng "chế độ nghiêm ngặt". Điều này chủ yếu là vì lý do bảo mật và đáng buồn là hiện tại không có sự thay thế nào cho việc này.


21

Điều này nên làm điều đó:

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

Đối với người gọi, chỉ cần sử dụng caller.toString().


8
Điều này làm việc cho tôi nhưng tôi nghĩ rằng có một lỗi đánh máy trong regrec của bạn. Tôi đã phải đưa ra các dấu chéo ngược trước[
Declan

4
@declan: vâng, bạn nói đúng. Thật đáng ngạc nhiên khi không ai khác chỉ ra rằng trong gần 3 năm, câu trả lời này đã có ở đây :-)
Andy E

@AndyE có lẽ không ai chỉ ra điều đó bởi vì một khi chúng ta thấy một biểu thức chính quy, chúng ta vào chế độ TL; DR và ​​tìm kiếm các câu trả lời khác;)
BitTickler

11

Điều này phải thuộc danh mục "những vụ hack xấu nhất thế giới", nhưng ở đây bạn đi.

Trước tiên, việc in tên của hàm hiện tại (như trong các câu trả lời khác) dường như đã hạn chế sử dụng đối với tôi, vì bạn đã biết chức năng này là gì!

Tuy nhiên, việc tìm ra tên của chức năng gọi có thể khá hữu ích cho chức năng theo dõi. Đây là một biểu thức chính quy, nhưng sử dụng indexOf sẽ nhanh hơn khoảng 3 lần:

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

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

me();

giải pháp tuyệt vời, nhưng hàm gọi # FYI Function là nhà phát triển không
chuẩn.mozilla.org/en-US/docs/Web/JavaScript/Reference/ trộm

Biết tên của hàm hiện tại có thể là điều cần thiết nếu hàm đó được tạo động từ cơ sở dữ liệu và cần thông tin ngữ cảnh bên trong hàm được khóa với tên hàm.
Paul Chernoch

9

Đây là một cách sẽ làm việc:

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

Sau đó, trong các bài kiểm tra của bạn:

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

});

Lưu ý rằng thử nghiệm thứ ba sẽ chỉ hoạt động nếu thử nghiệm được đặt trong / hồn / chức năng


7

Các getMyNamechức năng trong đoạn mã dưới đây trả về tên của hàm gọi. Đó là một hack và dựa vào tính năng không chuẩn : Error.prototype.stack. Lưu ý rằng định dạng của chuỗi được trả về Error.prototype.stackđược triển khai khác nhau trong các công cụ khác nhau, vì vậy điều này có thể sẽ không hoạt động ở mọi nơi:

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

Về các giải pháp khác: arguments.callee không được phép trong chế độ nghiêm ngặtFunction.prototype.callerphi tiêu chuẩn và không được phép vào chế độ nghiêm ngặt .


mở rộng điều này để cũng hiển thị vị trí trong chức năng và hỗ trợ các chức năng ẩn danh với: .replace (/ ^ \ s + at \ s (. +?) (?: \ s. *: | :) (. *?): (. * ?))? $ / g, '$ 1 ($ 2: $ 3)')
kofifus

Function.prototype.caller cũng không được phép trong chế độ nghiêm ngặt.
fijiaaron

1
Hoạt động hoàn hảo ngay cả đối với các chức năng mũi tên, câu trả lời bị đánh giá thấp
Hao Wu

3

Một trường hợp sử dụng khác có thể là một bộ điều phối sự kiện bị ràng buộc trong thời gian chạy:

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

Ưu điểm ở đây là bộ điều phối có thể dễ dàng được sử dụng lại và không phải nhận hàng đợi công văn làm đối số, thay vào đó, nó đi kèm với tên gọi ...

Cuối cùng, trường hợp chung được trình bày ở đây sẽ là "sử dụng tên hàm làm đối số để bạn không phải chuyển nó một cách rõ ràng" và điều đó có thể hữu ích trong nhiều trường hợp, như gọi lại tùy chọn jquery animate (), hoặc trong các cuộc gọi lại thời gian chờ / khoảng thời gian, (tức là bạn chỉ vượt qua một TÊN TÊN).


2

Tên của hàm hiện tại và cách có thể lấy được dường như đã thay đổi trong 10 năm qua, vì câu hỏi này đã được hỏi.

Bây giờ, không phải là một nhà phát triển web chuyên nghiệp, người biết về tất cả lịch sử của tất cả các trình duyệt đã từng tồn tại, đây là cách nó hoạt động với tôi trong trình duyệt chrome 2019:

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

Một số câu trả lời khác gặp phải một số lỗi chrome về mã javascript nghiêm ngặt và không có gì.


1

Vì bạn đã viết một hàm có tên foovà bạn biết đó là myfile.jslý do tại sao bạn cần lấy thông tin này một cách linh hoạt?

Điều đó đang được nói rằng bạn có thể sử dụng arguments.callee.toString()bên trong hàm (đây là biểu diễn chuỗi của toàn bộ hàm) và lấy ra giá trị của tên hàm.

Đây là một chức năng sẽ nhổ tên của chính nó:

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

5
Tôi đang làm việc với một trình xử lý lỗi và tôi muốn báo cáo chức năng gọi điện.
spugman

1

Một sự kết hợp của một vài câu trả lời tôi đã thấy ở đây. (Đã thử nghiệm trong 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);
}

Gọi RandomFunction () sẽ cảnh báo một chuỗi có chứa tên hàm.

Bản trình diễn JS Fiddle: http://jsfiddle.net/mjgqfhbe/


1

Câu trả lời cập nhật cho điều này có thể được tìm thấy tại câu trả lời này: https://stackoverflow.com/a/2161470/632495

và, nếu bạn không cảm thấy muốn nhấp vào:

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

1

Thông tin là thực tế vào năm 2016.


Kết quả khai báo hàm

Kết quả trong 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

Kết quả trong 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

Kết quả trong 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

Không hoạt động trong Firefox. Chưa được kiểm tra trên IE và Edge.


Kết quả cho biểu thức hàm

Kết quả trong NodeJS

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

Kết quả trong Chrome

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

Không hoạt động trong Firefox, Opera. Chưa được kiểm tra trên IE và Edge.

Ghi chú:

  1. Chức năng ẩn danh không có ý nghĩa để kiểm tra.
  2. Kiểm tra môi trường

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

Biến thể bản in:

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

f2(f1);  //Logs f1

Lưu ý chỉ có sẵn trong các công cụ tuân thủ ES6 / ES2015. Để xem thêm


0

Đây là một lót:

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

Như thế này:

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

0

Đây là một biến thể của câu trả lời của Igor Ostroumov :

Nếu bạn muốn sử dụng nó làm giá trị mặc định cho tham số, bạn cần xem xét cuộc gọi cấp hai đến 'người gọi':

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

Điều này sẽ tự động cho phép thực hiện có thể sử dụng lại trong nhiều chức năng.

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

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

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

function crow()
{
  bar();
}

foo();
crow();

Nếu bạn cũng muốn tên tệp, đây là giải pháp sử dụng câu trả lời từ F-3000 cho một câu hỏi khác:

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

Thử:

alert(arguments.callee.toString());

3
Điều đó sẽ trả về toàn bộ chức năng dưới dạng một chuỗi
Andy E

-7

Câu trả lời ngắn gọn: alert(arguments.callee.name);


12
"nom" là "tên" trong tiếng Pháp. Liệu loại chi tiết này thay đổi giữa các phiên bản ngôn ngữ của trình duyệt? Tôi sẽ không nghĩ như vậy.
argyle
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.