해당 함수 내에서 함수 이름을 얻는 방법은 무엇입니까?


263

해당 함수 내에서 함수 이름에 어떻게 액세스 할 수 있습니까?

// parasitic inheritance
var ns.parent.child = function() {
  var parent = new ns.parent();
  parent.newFunc = function() {

  }
  return parent;
}

var ns.parent = function() {
  // at this point, i want to know who the child is that called the parent
  // ie
}

var obj = new ns.parent.child();

음, 부모에서, ns [child] [schema] 또는 ns [child] [dbService]와 같은 규칙에 따라 다른 함수에 액세스 할 수 있습니다. 그것이 없으면 모든 하위 클래스에서 이러한 참조를 하드 코딩해야합니다.
— Scott Klarenbach

왜 자식 함수를 부모에게 인수로 전달하지 않습니까? var parent = new ns.parent (this);
— plodder

수십 명의 그러한 조회와 수십 명의 자녀가 있기 때문입니다. 그것은 현재 내가하고있는 일이지만 매번 동일하며 파생 된 함수를 기반으로 중복 논리를 부모 내부에 한 번만 배치 할 수 있다면 완벽합니다.
— Scott Klarenbach

참조, 그것은 내가 원하는 자식 함수가 아니라 사용되는 명명 규칙입니다. 그 명명 규칙은 현재 자식 객체에 정의되어 있지 않지만 시스템 전체에서 그 자식과 관련된 다른 함수를로드하는 데 사용될 수 있기 때문입니다.
— Scott Klarenbach

1
@Scott 나는 당신의 복잡성과 코드 구조를 관리하는 데 필요한 다른 사람들과 동의합니다. 이러한 종류의 하드 커플 링은 잘못된 디자인 결정이며 혼란을 일으킬 것입니다. @SimeVidas 당신의 위대한 네크로맨서 :)
— Raynos

답변:


163

ES5에서 가장 좋은 방법은 다음과 같습니다.

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

사용 Function.caller은 비표준입니다. Function.caller그리고 arguments.callee모두 엄격 모드에서 금지된다.

편집 : 아래의 nus 정규식 기반 답변은 동일한 것을 달성하지만 더 나은 성능을 제공합니다!

ES6에서는을 사용할 수 있습니다 myFunction.name.

참고 : 일부 JS 축소 기는 더 나은 압축을 위해 함수 이름을 버릴 수 있습니다. 이를 피하기 위해 설정을 조정해야 할 수도 있습니다.


이것이 익명의 기능으로 인해 나에게 충분한 대답을하지는 못했지만, 이것을 수행하는 아이디어를 얻었습니다. fun.toString().substr(0, 100)필요한 기능을 찾기에 충분할 것입니다. 영감을 주셔서 감사합니다!
— Campbeln

3
myFunction.nameES6에서는 Yup 이 가장 좋습니다.
— Vlad A Ionescu

15
myFunction.name함수 이름을 입력 하면 요점은 무엇입니까 ? 마법 변수의 목적을 무너 뜨립니다.
— adi518

2
@ adi518 : 반드시 ... 당신이 기능의 배열을 생각하지 당신은에 사용, 그것은 반복 / foreach는 ..then arr[index].name것 또한 작업 :
— Debasish Chowdhury

2
@ adi518 그것은 쓸모가 없습니다. IDE 내에서 함수의 이름을 바꾸면 myFunction.name업데이트됩니다. 물론, intelliJ는 문자열 내에서 식별자 이름 변경을 지원하지만, 일관성이 떨어지고 누군가가 "문자열에서 검색"옵션을 선택하지 않으면 구식이 될 것입니다. myFunction.name문자열을 하드 코딩하는 것보다 약간 더 나은 선택입니다.
— byxor December

141

ES6 (아래 센디 할림의 답변에서 영감을 얻음) :

myFunction.name

MDN에 대한 설명 . 2015 년 현재 nodejs 및 IE를 제외한 모든 주요 브라우저에서 작동합니다.

참고 : 바인딩 된 함수에서는 " bound <originalName>"가 표시됩니다. 원래 이름을 얻으려면 "바운드"를 제거해야합니다.


ES5 (Vlad의 답변에서 영감을 받음) :

함수에 대한 참조가있는 경우 다음을 수행 할 수 있습니다.

function functionName( func )
{
    // Match:
    // - ^          the beginning of the string
    // - function   the word 'function'
    // - \s+        at least some white space
    // - ([\w\$]+)  capture one or more valid JavaScript identifier characters
    // - \s*        optionally followed by white space (in theory there won't be any here,
    //              so if performance is an issue this can be omitted[1]
    // - \(         followed by an opening brace
    //
    var result = /^function\s+([\w\$]+)\s*\(/.exec( func.toString() )

    return  result  ?  result[ 1 ]  :  '' // for an anonymous function there won't be a match
}
  • 나는 이것에 대해 단위 테스트를 실행하지 않았거나 구현 차이를 확인했지만 원칙적으로 주석을 남기지 않으면 작동해야합니다.
  • 참고 : 바운드 함수에서는 작동하지 않습니다
  • 참고 : 그 caller와 callee사용되지 않는 것으로 간주한다.

[1] 합법적이고 종종 구문 강조 도구가 함수 이름과 괄호 사이의 공백을 고려하지 못하기 때문에 여기에 포함 시켰습니다. 반면에 여기에 공백이 포함될 .toString () 구현을 알지 못하므로 생략 할 수 있습니다.


원래 질문에 대한 답으로 기생 적 상속을 중단하고 좀 더 전통적인 OOP 디자인 패턴을 사용합니다. C ++을 모방 한 기능 세트 (아직 완전하지는 않지만 대부분)를 사용하여 JavaScript에서 OOP 코드를 편안하게 작성하기 위해 TidBits.OoJs 를 작성했습니다 .

의견에서 정보 parent요구 사항을 생성자에게 전달하지 않기를 바랍니다 . 나는 전통적인 디자인 패턴이 당신의 의존성을 분명하고 강제하는 것이 일반적으로 좋은 것으로 간주되기 때문에 그 패턴에서 당신을 구할 수 없다는 것을 인정해야합니다.

또한 익명의 기능을 피하는 것이 좋습니다. 모든 것이 단지 "익명 함수"로 나타나기 때문에 PITA의 디버깅 및 프로파일 링 만 수행하며, 내가 알고있는 이점은 없습니다.


3
좋은 정규식! 다음은 코드가 많은 경우에 가장 빠른 성능 테스트입니다. 일반적으로 RegEx가 여기에서 평균 JS 속도보다 약 2 배 빠릅니다. jsperf.com/get-function-name/2
— Beejor

@Tomasz 안녕하세요, 지적 해 주셔서 감사합니다. 나는 몰랐다. 바운드 함수는 실제로 원래 함수를 래핑하는 새로운 함수입니다. ecmascript 표준 § 19.2.3.2는 새 기능의 이름이 "bound"+ originalName이되도록 정의합니다. toString 메소드는 바인드 함수에서도 작동하지 않습니다. 바인드 된 단어를 제거해야합니다.

함수 이름을 입력하면 myFunction.name의 요점은 무엇입니까? 마법 변수의 목적을 무너 뜨립니다.
— Borjovsky

React Native를 사용하는 경우 제대로 작동하지 않을 수 있습니다. 엑스포 버전 36으로 작업하고있는 RN 프로젝트가 있는데 구성 요소 메소드의 .name속성이 무엇이든간에 "값"문자열로 표시되었습니다. 이상하게도 박람회 응용 프로그램에서 테스트하는 동안 문제가 없었지만 실제 응용 프로그램으로 컴파일되면 자동으로 충돌합니다.
— 앤디 코먼

64

당신이하고있는 일은 명명되지 않은 함수를 변수에 할당하는 것입니다. 대신 이름이 지정된 함수 표현식이 필요합니다 ( http://kangax.github.com/nfe/ ).

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

그러나 브라우저 간 브라우저의 양이 확실하지 않습니다. IE6에는 함수의 이름이 외부 범위로 누출되는 문제가 있습니다. 또한 arguments.callee는 더 이상 사용되지 않으며를 사용하면 오류가 발생합니다 strict mode.


1
이전 버전의 Safari 브라우저에서는 작동하지 않습니다.
— Anubhav Gupta

17

어느 constructor속성 노출 name함수 이름입니다. 당신은 액세스 constructor인스턴스를 통해 (사용 new) 또는를 prototype:

function Person() {
  console.log(this.constructor.name); //Person
}

var p = new Person();
console.log(p.constructor.name); //Person

console.log(Person.prototype.constructor.name);  //Person

6
첫 번째 console.log통화 기록 window또는 Object내가 실행 한 위치에 따라 다릅니다 Person.
— Bart S

"new"를 사용하여 인스턴스화 했습니까? 그렇지 않으면 작동하지 않습니다.
— roland

14

내 인생에서 쓴 가장 멍청한 것 같지만 재미있다 : D

function getName(d){
  const error = new Error();
  const firefoxMatch = (error.stack.split('\n')[0 + d].match(/^.*(?=@)/) || [])[0];
  const chromeMatch = ((((error.stack.split('at ') || [])[1 + d] || '').match(/(^|\.| <| )(.*[^(<])( \()/) || [])[2] || '').split('.').pop();
  const safariMatch = error.stack.split('\n')[0 + d];

  // firefoxMatch ? console.log('firefoxMatch', firefoxMatch) : void 0;
  // chromeMatch ? console.log('chromeMatch', chromeMatch) : void 0;
  // safariMatch ? console.log('safariMatch', safariMatch) : void 0;

  return firefoxMatch || chromeMatch || safariMatch;
}

d-스택 깊이. 0-이 함수 이름, 1부모 등을 반환합니다 .
[0 + d]-이해를 위해서-무슨 일이;
firefoxMatch-사파리에서 작동하지만 Mac 소유자가 담배를 피우고 돌아 와서 나를 몰아 냈기 때문에 테스트 할 시간이 거의 없었습니다. '(

테스트 :

function limbo(){
  for(let i = 0; i < 4; i++){
    console.log(getName(i));
  }
}
function lust(){
  limbo();
}
function gluttony(){
  lust();
}

gluttony();

결과 :
크롬 :
여기에 이미지 설명을 입력하십시오

Fitefox :
여기에 이미지 설명을 입력하십시오

이 솔루션은 단지 재미 를 위해서만 만들어졌습니다 ! 실제 프로젝트에는 사용하지 마십시오. ES 사양에 의존하지 않고 브라우저 구현에만 의존합니다. 다음 크롬 / 파이어 폭스 / 사파리 업데이트 후에 깨질 수 있습니다.
그보다 더 많은 오류 (ha) 처리가 없습니다- d스택 길이보다 길면 오류가 발생합니다.
다른 wrowsers 오류의 메시지 패턴-오류가 발생합니다.
ES6 클래스 ( .split('.').pop())에서 작동해야 하지만, 병이 나면 오류가 발생할 수 있습니다.


13

이것은 당신을 위해 일할 수 있습니다 :

function foo() { bar(); }

function bar() { console.log(bar.caller.name); }

foo ()를 실행하면 "foo"가 출력되거나 익명 함수에서 호출하면 정의되지 않습니다.

생성자에서도 작동합니다.이 경우 호출 생성자의 이름을 출력합니다 (예 : "Foo").

자세한 내용은 여기 : https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/Caller

그들은 표준이 아니라고 주장하지만 Firefox, Safari, Chrome, Opera 및 IE와 같은 모든 주요 브라우저에서 지원한다고 주장합니다.


엄격 모드에서는 사용할 수 없습니다 ... mmm
— Ka Mok

8

당신은 할 수 없습니다. 함수는 표준에 따라 이름을 갖지 않습니다 (mozilla에는 그러한 속성이 있지만). 이름이있는 변수에만 할당 할 수 있습니다.

또한 귀하의 의견 :

// access fully qualified name (ie "my.namespace.myFunc")

함수 my.namespace.myFunc.getFn 안에 있습니다.

당신이 할 수있는 일은 new에 의해 생성 된 객체의 생성자를 반환하는 것입니다

그래서 당신은 말할 수

var obj = new my.namespace.myFunc();
console.info(obj.constructor); //my.namespace.myFunc

1
상속 체인을 전달하기 때문에 func 내부에 필요하며 간결하게하기 위해 해당 항목을 생략했습니다.
— Scott Klarenbach

1
'this'는 함수를 호출 한 인스턴스입니다. 따라서 부모 함수 내부에 'this'인 경우 호출 한 함수의 인스턴스를 제공합니다. 그것이 당신이 필요로하는 전부입니다-왜 당신도 이름이 필요한지 확실치 않습니다
— plodder

1
음, 부모에서, ns [child] [schema] 또는 ns [child] [dbService]와 같은 규칙에 따라 다른 함수에 액세스 할 수 있습니다. 그것이 없으면 모든 하위 클래스에서 이러한 참조를 하드 코딩해야합니다.
— Scott Klarenbach

1
이름을 찾는 나의 유스 케이스는 console.error 메시지를 더 쉽게 구성하여 스택 덤프로 되돌릴 필요없이 메시지가 어디서 왔는지 알려줍니다. 예를 들어 console.error ({ 'error': {self.name reference} + "입력 매개 변수 오류"). 매번 텍스트를 중지하고 변경할 필요가없는 경우 여러 기능에서 반복되는 오류 메시지를 잘라 내기 / 붙여 넣기가 훨씬 쉬워집니다. 제 경우에는 여러 약속 호출에서 약속 오류를 반환합니다. 어떤 약속 / 기능이 오류를 생성했는지 알고 싶습니다.
— Scott

7

Error.stack을 지원하는 브라우저에 사용할 수 있습니다 (거의 전부는 아님)

function WriteSomeShitOut(){ 
  var a = new Error().stack.match(/at (.*?) /);
  console.log(a[1]);
} 
WriteSomeShitOut();

물론 이것은 현재 기능에 대한 것이지만 아이디어를 얻습니다.

코딩하는 동안 행복한 침 흘리기


4

당신이 사용할 수있는 name익명 함수를 사용하지 않는 한 property를 하여 함수 이름을 가져올

예를 들면 다음과 같습니다.

var Person = function Person () {
  this.someMethod = function () {};
};

Person.prototype.getSomeMethodName = function () {
  return this.someMethod.name;
};

var p = new Person();
// will return "", because someMethod is assigned with anonymous function
console.log(p.getSomeMethodName());

이제 명명 된 함수를 사용해 봅시다

var Person = function Person () {
  this.someMethod = function someMethod() {};
};

지금 당신은 사용할 수 있습니다

// will return "someMethod"
p.getSomeMethodName()

4

다음과 같이 생성자 이름을 사용할 수 있습니다.

{your_function}.prototype.constructor.name

이 코드는 단순히 메서드 이름을 반환합니다.


3

Function.name 메소드를 ECMAScript 6사용할 수있는 부분으로

function doSomething() {}

alert(doSomething.name); // alerts "doSomething"

ReactJS에서 이것을 추가해야합니다 : console.log (this.doSomething.name);
— Bitclaw

2
그것은 기능 밖입니다
— Scott

3

당신은 사용할 수 있습니다Function.name :

대부분의 JavaScript 구현에서 생성자 참조가 범위 내에 있으면 이름 속성 (예 : Function.name 또는 Object.constructor.name)에서 해당 문자열 이름을 가져올 수 있습니다.

당신은 사용할 수 있습니다Function.callee :

기본 arguments.caller메소드는 더 이상 사용되지 않지만 대부분의 브라우저는을 지원 Function.caller하여 실제 호출 객체 (코드 본문)를 리턴합니다. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ 함수 / 호출자? redirectlocale = ko-KR & redirectslug = JavaScript % 2FReference % 2FGlobal_Objects % 2FFunction % 2Fcaller

소스 맵을 만들 수 있습니다 .

객체 자체가 아닌 리터럴 함수 시그니처 ( "이름")가 필요한 경우 API 문자열 값의 배열 참조를 만드는 등 좀 더 사용자 정의 된 무언가를 사용해야 할 수도 있습니다. 자주 액세스하십시오. https://github.com/mozilla/source-mapObject.keys() : 당신은 문자열 배열을 사용하여 함께 매핑 하거나 더 큰 프로젝트를 위해 GitHub의 Mozilla 소스 맵 라이브러리를 볼 수 있습니다 : https://github.com/mozilla/source-map


2

나는 이것이 오래된 질문이라는 것을 알고 있지만 최근에는 디버깅 목적으로 React Component의 메소드를 장식하는 동안 비슷한 문제에 직면 해있다. 로 사람들은 이미 말했다, arguments.caller그리고 arguments.callee아마 당신의 반작용 transpiling에서 기본적으로 활성화되어 엄격 모드에서 금지된다. React에서 모든 클래스 함수의 이름이 지정되므로 실제로이 작업을 수행 할 수 있기 때문에 비활성화하거나 다른 해킹을 만들 수 있습니다.

Component.prototype.componentWillMount = function componentWillMount() {
    console.log('Callee name: ', this.__proto__.constructor.toString().substr(0,30));
...
}

1

이것은 나를 위해 일했습니다.

function AbstractDomainClass() {
    this.className = function() {
        if (!this.$className) {
            var className = this.constructor.toString();
            className = className.substr('function '.length);
            className = className.substr(0, className.indexOf('('));
            this.$className = className;
        }
        return this.$className;
    }
}

테스트 코드 :

var obj = new AbstractDomainClass();
expect(obj.className()).toBe('AbstractDomainClass');

1

비슷한 문제가 있었고 다음과 같이 해결했습니다.

Function.prototype.myname = function() {
   return this.toString()
       .substr( 0, this.toString().indexOf( "(" ) )
       .replace( "function ", "" ); 
}

이 코드는이 토론의 맨 위에서 이미 읽은 하나의 응답을보다 편안한 방식으로 구현합니다. 이제 함수 객체의 이름을 검색하는 멤버 함수가 있습니다. 전체 스크립트는 다음과 같습니다.

<script language="javascript" TYPE="text/javascript">

    Function.prototype.myname = function() { 
        return this.toString()
            .substr( 0, this.toString().indexOf( "(" ) )
            .replace("function ", "" ); 
    }
    function call_this( _fn ) { document.write( _fn.myname() ); }
    function _yeaaahhh() { /* do something */ }
    call_this( _yeaaahhh ); 

</script>


0

ES5, ES6, 모든 브라우저 및 엄격 모드 기능에서 작동합니다.

명명 된 함수를 사용하는 방법은 다음과 같습니다.

(function myName() {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at myName (<anonymous>:2:15)

익명 함수로 보이는 방법은 다음과 같습니다.

(() => {
  console.log(new Error().stack.split(/\r\n|\r|\n/g)[1].trim());
})();
at <anonymous>:2:15

이는 브라우저마다 다른 결과를 생성합니다. Chrome : at myName (<anonymous>:2:15)Firefox :@debugger eval code:3:3
— jkdev

(함수 myName () {console.log (새 오류 () .stack.split (/ \ r \ n | \ r | \ n / g) [1] .trim (). split ( "") [1]) ;}) ();
— Zibri



-3

실행중인 기능 내에서 기능 이름을 얻는 쉬운 방법.

function x(){alert(this.name)};x()


1
GUID를 제공합니다
— Tamir Daniely

1
this그것 의 내용을 알고 기본적으로 무엇이든 될 수 있습니다. 시도(function(){console.log(this.name);}).bind({name: "put basically anything here even an object maybe a 1TB string maybe a class definition"})()
— Valen
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.