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


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
}
  • 나는 이것에 대해 단위 테스트를 실행하지 않았거나 구현 차이를 확인했지만 원칙적으로 주석을 남기지 않으면 작동해야합니다.
  • 참고 : 바운드 함수에서는 작동하지 않습니다
  • 참고 : 그 callercallee사용되지 않는 것으로 간주한다.

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