Development Tip

JavaScript에서 호출자 함수를 어떻게 찾습니까?

yourdevel 2020. 9. 28. 10:16
반응형

JavaScript에서 호출자 함수를 어떻게 찾습니까?


function main()
{
   Hello();
}

function Hello()
{
  // How do you find out the caller function is 'main'?
}

호출 스택을 찾는 방법이 있습니까?


function Hello()
{
    alert("caller is " + Hello.caller);
}

이 기능은 다음 에서 비표준 입니다 Function.caller.

비표준
이 기능은 비표준이며 표준 트랙에 없습니다. 웹에 접하는 프로덕션 사이트에서는 사용하지 마십시오. 모든 사용자에게 작동하지 않습니다. 구현간에 큰 비 호환성이있을 수 있으며 향후 동작이 변경 될 수 있습니다.


다음은 더 이상 최신 Javascript에서 지원되지 않는 2008의 이전 답변입니다.

function Hello()
{
    alert("caller is " + arguments.callee.caller.toString());
}

StackTrace

브라우저 별 코드를 사용하여 전체 스택 추적을 찾을 수 있습니다. 좋은 것은 누군가 이미 그것을 만들었다는 것입니다 . 다음은 GitHub프로젝트 코드입니다 .

그러나 모든 뉴스가 좋은 것은 아닙니다.

  1. 정말 (읽기 스택 추적이 너무 조심해야 얻을 둔화되고 이상).

  2. 스택 추적을 읽을 수 있도록 함수 이름을 정의해야합니다. 다음과 같은 코드가있는 경우 :

    var Klass = function kls() {
       this.Hello = function() { alert(printStackTrace().join('\n\n')); };
    }
    new Klass().Hello();
    

    Google 크롬은 경고를 표시 ... kls.Hello ( ...하지만 대부분의 브라우저는 키워드 바로 뒤에 함수 이름을 예상하고 function이를 익명 함수로 처리합니다. 함수에 Klass이름 kls지정하지 않으면 Chrome조차도 이름 을 사용할 수 없습니다 .

    {guess: true}그건 그렇고, printStackTrace 함수에 옵션을 전달할 수는 있지만 그렇게함으로써 실질적인 개선을 찾지 못했습니다.

  3. 모든 브라우저가 동일한 정보를 제공하는 것은 아닙니다. 즉, 매개 변수, 코드 열 등입니다.


호출자 함수 이름

그건 그렇고, (대부분의 브라우저에서 IE가 아닌) 호출자 함수의 이름 만 원한다면 다음을 사용할 수 있습니다.

arguments.callee.caller.name

그러나이 이름은 function키워드 다음의 이름이됩니다 . 전체 기능의 코드를 얻지 않고는 (Google 크롬에서도) 그 이상을 얻을 방법을 찾지 못했습니다.


발신자 기능 코드

나머지 베스트 답변을 요약합니다 (Pablo Cabrera, nourdine 및 Greg Hewgill 작성). 사용할 수있는 유일한 크로스 브라우저이자 정말 안전한 방법은 다음과 같습니다.

arguments.callee.caller.toString();

호출자 함수 코드 가 표시 됩니다. 슬프게도 이것만으로는 충분하지 않습니다. 이것이 바로 StackTrace와 호출자 함수 이름에 대한 팁을 제공하는 이유입니다 (브라우저 간은 아니지만).


요약하면 (그리고 더 명확하게) ...

이 코드 :

function Hello() {
    alert("caller is " + arguments.callee.caller.toString());
}

다음과 같습니다.

function Hello() {
    alert("caller is " + Hello.caller.toString());
}

함수의 이름을 "Hello"에서 "Ciao"로 바꾸어도 모든 것을 작동시킬 수 있기 때문에 첫 번째 비트는 더 이식성이 뛰어납니다.

후자의 경우 호출 된 함수의 이름 (Hello)을 리팩터링하기로 결정한 경우 모든 발생을 변경해야합니다.


전체 스택 추적을 얻을 수 있습니다.

arguments.callee.caller
arguments.callee.caller.caller
arguments.callee.caller.caller.caller

발신자가 null.

참고 : 재귀 함수에서 무한 루프가 발생합니다.


"자바 스크립트에서"라고 언급 한 것을 알고 있지만 디버깅이 목적이라면 브라우저의 개발자 도구를 사용하는 것이 더 쉽다고 생각합니다. 이것이 Chrome에서 보이는 방식 여기에 이미지 설명 입력입니다. 스택을 조사 할 디버거를 놓기 만하면됩니다.


저는 보통 (new Error()).stackChrome에서 사용 합니다. 좋은 점은 호출자가 함수를 호출 한 줄 번호도 제공한다는 것입니다. 단점은 스택의 길이를 10으로 제한한다는 것입니다. 이것이 제가 처음에이 페이지를 찾은 이유입니다.

(실행 중에 저수준 생성자에서 콜 스택을 수집하고 나중에보고 디버그하기 위해 이것을 사용하고 있으므로 중단 점을 설정하는 것은 수천 번에 해당하므로 쓸모가 없습니다)


IE <11에서 실행하지 않으려면 console.trace () 가 적합합니다.

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

main()
// Hello @ VM261:9
// main @ VM261:4

Function.Caller를 사용하여 호출 함수를 가져올 수 있습니다. argument.caller를 사용하는 이전 방법은 구식으로 간주됩니다.

다음 코드는 그 사용법을 보여줍니다.

function Hello() { return Hello.caller;}

Hello2 = function NamedFunc() { return NamedFunc.caller; };

function main()
{
   Hello();  //both return main()
   Hello2();
}

오래된 argument.caller에 대한 참고 사항 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

Function.caller는 비표준입니다 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/caller


function Hello() {
    alert(Hello.caller);
}

그것은 사용하기 더 안전 *arguments.callee.caller하기 때문에 arguments.caller되어 사용되지 ...


이것은 꽤 해결 된 질문처럼 보이지만 최근에 피 호출자가 '엄격 모드'에서 허용되지 않는다는 것을 알게 되었으므로 내 자신의 용도로 호출되는 경로를 가져올 클래스를 작성했습니다. 작은 도우미 라이브러리일부이며 코드를 독립 실행 형으로 사용하려면 호출자의 스택 추적을 반환하는 데 사용되는 오프셋을 변경합니다 (2 대신 1 사용).

function ScriptPath() {
  var scriptPath = '';
  try {
    //Throw an error to generate a stack trace
    throw new Error();
  }
  catch(e) {
    //Split the stack trace into each line
    var stackLines = e.stack.split('\n');
    var callerIndex = 0;
    //Now walk though each line until we find a path reference
    for(var i in stackLines){
      if(!stackLines[i].match(/http[s]?:\/\//)) continue;
      //We skipped all the lines with out an http so we now have a script reference
      //This one is the class constructor, the next is the getScriptPath() call
      //The one after that is the user code requesting the path info (so offset by 2)
      callerIndex = Number(i) + 2;
      break;
    }
    //Now parse the string for each section we want to return
    pathParts = stackLines[callerIndex].match(/((http[s]?:\/\/.+\/)([^\/]+\.js)):/);
  }

  this.fullPath = function() {
    return pathParts[1];
  };

  this.path = function() {
    return pathParts[2];
  };

  this.file = function() {
    return pathParts[3];
  };

  this.fileNoExt = function() {
    var parts = this.file().split('.');
    parts.length = parts.length != 1 ? parts.length - 1 : 1;
    return parts.join('.');
  };
}

나는 이것을 할 것이다 :

function Hello() {
  console.trace();
}

이것에 액세스하십시오 :

arguments.callee.caller.name

콘솔에서 오류 스택을 기록하십시오. 그런 다음 어떻게 전화를 받고 있는지 알 수 있습니다.

const hello = () => {
  console.log(new Error('I was called').stack)
}

const sello = () => {
  hello()
}

sello()


2018 업데이트

caller엄격 모드에서는 금지되어 있습니다 . 다음은 (비표준) Error스택을 사용하는 대안 입니다.

다음 함수는 Firefox 52 및 Chrome 61-71에서 작업을 수행하는 것으로 보이지만 해당 구현은 두 브라우저의 로깅 형식에 대해 많은 가정을하고 예외가 발생하고 두 개의 정규식을 실행할 수 있다는 점을 고려하여주의해서 사용해야합니다. 완료되기 전에 일치.

'use strict';
const fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;

function fnName(str) {
  const regexResult = fnNameMatcher.exec(str);
  return regexResult[1] || regexResult[2];
}

function log(...messages) {
  const logLines = (new Error().stack).split('\n');
  const callerName = fnName(logLines[1]);

  if (callerName !== null) {
    if (callerName !== 'log') {
      console.log(callerName, 'called with:', ...messages);
    } else {
      console.log(fnName(logLines[2]), 'called with:', ...messages);
    }
  } else {
    console.log(...messages);
  }
}

function foo() {
  log('hi', 'there');
}

(function main() {
  foo();
}());


여기에 내 바이올린을 추가하고 싶었습니다.

http://jsfiddle.net/bladnman/EhUm3/

나는 이것이 크롬, 사파리 및 IE (10 및 8)임을 테스트했습니다. 잘 작동합니다. 중요한 기능은 하나뿐이므로 큰 바이올린에 겁이 나면 아래를 읽으십시오.

참고 :이 바이올린에는 내 자신의 "보일러 플레이트"가 상당히 많이 있습니다. 원하는 경우 모든 것을 제거하고 분할을 사용할 수 있습니다. 그것은 제가 의지하게 된 매우 안전한 "기능의 집합 일뿐입니다.

거기에 "JSFiddle"템플릿이 있는데,이 템플릿은 간단한 조작을 위해 많은 바이올린에 사용합니다.


코드가 아닌 함수 이름 만 원하고 브라우저 독립적 인 솔루션을 원하면 다음을 사용하십시오.

var callerFunction = arguments.callee.caller.toString().match(/function ([^\(]+)/)[1];

위의 경우 배열에 [1] 요소가 없기 때문에 호출자 함수가없는 경우 오류가 반환됩니다. 이 문제를 해결하려면 아래를 사용하십시오.

var callerFunction = (arguments.callee.caller.toString().match(/function ([^\(]+)/) === null) ? 'Document Object Model': arguments.callee.caller.toString().match(/function ([^\(]+)/)[1], arguments.callee.toString().match(/function ([^\(]+)/)[1]);

그냥 당신이에 있음을 알려 할 폰갭 / 안드로이드name 나던 작동하는 것 같다. 그러나 arguments.callee.caller.toString()트릭을 할 것입니다.


여기에서를 제외한 모든 것은 RegExp를 사용하여 functionname에서 제거됩니다 caller.toString().

<!DOCTYPE html>
<meta charset="UTF-8">
<title>Show the callers name</title><!-- This validates as html5! -->
<script>
main();
function main() { Hello(); }
function Hello(){
  var name = Hello.caller.toString().replace(/\s\([^#]+$|^[^\s]+\s/g,'');
  name = name.replace(/\s/g,'');
  if ( typeof window[name] !== 'function' )
    alert ("sorry, the type of "+name+" is "+ typeof window[name]);
  else
    alert ("The name of the "+typeof window[name]+" that called is "+name);
}
</script>

다음은 전체 스택 추적얻는 함수입니다 .

function stacktrace() {
var f = stacktrace;
var stack = 'Stack trace:';
while (f) {
  stack += '\n' + f.name;
  f = f.caller;
}
return stack;
}

heystewart의 답변JiarongWu의 답변은 모두 Error객체가 stack.

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

function main() {
  Hello();
}

function Hello() {
  var stack;
  try {
    throw new Error();
  } catch (e) {
    stack = e.stack;
  }
  // N.B. stack === "Error\n  at Hello ...\n  at main ... \n...."
  var m = stack.match(/.*?Hello.*?\n(.*?)\n/);
  if (m) {
    var caller_name = m[1];
    console.log("Caller is:", caller_name)
  }
}

main();

다른 브라우저는 다른 문자열 형식으로 스택을 표시합니다.

Safari : Caller is: main@https://stacksnippets.net/js:14:8 Firefox : Caller is: main@https://stacksnippets.net/js:14:3 Chrome : Caller is: at main (https://stacksnippets.net/js:14:3) IE Edge : Caller is: at main (https://stacksnippets.net/js:14:3) IE : Caller is: at main (https://stacksnippets.net/js:14:3)

대부분의 브라우저는 var stack = (new Error()).stack. Internet Explorer에서 스택은 정의되지 않습니다. 스택을 검색하려면 실제 예외를 발생시켜야합니다.

결론 : 개체 stack에서를 사용하여 "main"이 "Hello"에 대한 호출자임을 확인할 수 있습니다 Error. 실제로 callee/ caller접근 방식이 작동하지 않는 경우에도 작동합니다. 또한 컨텍스트, 즉 소스 파일과 줄 번호를 보여줍니다. 그러나 솔루션을 교차 플랫폼으로 만들려면 노력이 필요합니다.


ES6 및 Strict 모드에서 다음을 사용하여 Caller 함수를 가져옵니다.

console.log((new Error()).stack.split("\n")[2].trim().split(" ")[1])

호출자가 없거나 이전 스택이없는 경우 위 줄에서 예외가 발생합니다. 그에 따라 사용하십시오.


다음 코드를 시도하십시오.

function getStackTrace(){
  var f = arguments.callee;
  var ret = [];
  var item = {};
  var iter = 0;

  while ( f = f.caller ){
      // Initialize
    item = {
      name: f.name || null,
      args: [], // Empty array = no arguments passed
      callback: f
    };

      // Function arguments
    if ( f.arguments ){
      for ( iter = 0; iter<f.arguments.length; iter++ ){
        item.args[iter] = f.arguments[iter];
      }
    } else {
      item.args = null; // null = argument listing not supported
    }

    ret.push( item );
  }
  return ret;
}

Firefox-21 및 Chromium-25에서 나를 위해 일했습니다.


이 문제를 해결하는 또 다른 방법은 호출하는 함수의 이름을 매개 변수로 전달하는 것입니다.

예를 들면 :

function reformatString(string, callerName) {

    if (callerName === "uid") {
        string = string.toUpperCase();
    }

    return string;
}

이제 다음과 같이 함수를 호출 할 수 있습니다.

function uid(){
    var myString = "apples";

    reformatString(myString, function.name);
}

내 예에서는 함수 이름의 하드 코딩 된 검사를 사용하지만 스위치 문이나 다른 논리를 사용하여 원하는 작업을 쉽게 수행 할 수 있습니다.


내가 아는 한, 우리는 이와 같은 주어진 소스에서 이것을위한 두 가지 방법이 있습니다.

  1. arguments.caller

    function whoCalled()
    {
        if (arguments.caller == null)
           console.log('I was called from the global scope.');
        else
           console.log(arguments.caller + ' called me!');
    }
    
  2. Function.caller

    function myFunc()
    {
       if (myFunc.caller == null) {
          return 'The function was called from the top!';
       }
       else
       {
          return 'This function\'s caller was ' + myFunc.caller;
        }
    }
    

당신의 대답이 있다고 생각하십시오 :).


위의 모든 솔루션이 로켓 과학처럼 보이는 이유. 한편,이 스 니펫보다 더 복잡해서는 안됩니다. 이 사람에 대한 모든 크레딧

JavaScript에서 호출자 함수를 어떻게 찾습니까?

var stackTrace = function() {

    var calls = [];
    var caller = arguments.callee.caller;

    for (var k = 0; k < 10; k++) {
        if (caller) {
            calls.push(caller);
            caller = caller.caller;
        }
    }

    return calls;
};

// when I call this inside specific method I see list of references to source method, obviously, I can add toString() to each call to see only function's content
// [function(), function(data), function(res), function(l), function(a, c), x(a, b, c, d), function(c, e)]

나는이 질문에 대한 질문과 현재 현상금을 모두 해결하려고 노력하고 있습니다.

현상금은 호출자가 엄격 모드 에서 얻어 져야하며 , 이것이 수행되는 것을 볼 수있는 유일한 방법 은 엄격 모드 외부 에서 선언 된 함수를 참조하는 것입니다 .

예를 들어 다음은 비표준이지만 Chrome, Edge 및 Firefox의 이전 버전 (2016 년 3 월 29 일) 및 현재 버전 (2018 년 8 월 1 일)에서 테스트되었습니다.

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

'use strict';
function main()
{
   // Original question:
   Hello();
   // Bounty question:
   (function() { console.log('Anonymous function called by ' + caller().name); })();
}

function Hello()
{
   // How do you find out the caller function is 'main'?
   console.log('Hello called by ' + caller().name);
}

main();


어떤 이유로 기능이 정말로 필요하고 브라우저 간 호환이 가능하고 엄격한 항목에 대해 걱정하지 않고 앞으로 호환되도록하려면 다음 참조를 전달하십시오.

function main()
{
   Hello(this);
}

function Hello(caller)
{
    // caller will be the object that called Hello. boom like that... 
    // you can add an undefined check code if the function Hello 
    // will be called without parameters from somewhere else
}

다음 코드가 도움이 될 것이라고 생각합니다.

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

코드를 실행하십시오.

window.fnPureLog = function(sStatement, anyVariable) {
    if (arguments.length < 1) { 
        throw new Error('Arguments sStatement and anyVariable are expected'); 
    }
    if (typeof sStatement !== 'string') { 
        throw new Error('The type of sStatement is not match, please use string');
    }
    var oCallStackTrack = new Error();
    console.log(oCallStackTrack.stack.replace('Error', 'Call Stack:'), '\n' + sStatement + ':', anyVariable);
}

function fnBsnCallStack1() {
    fnPureLog('Stock Count', 100)
}

function fnBsnCallStack2() {
    fnBsnCallStack1()
}

fnBsnCallStack2();

로그는 다음과 같습니다.

Call Stack:
    at window.fnPureLog (<anonymous>:8:27)
    at fnBsnCallStack1 (<anonymous>:13:5)
    at fnBsnCallStack2 (<anonymous>:17:5)
    at <anonymous>:20:1 
Stock Count: 100

이전 답변 중 어느 것도 내가 찾던 것과 같이 작동하지 않기 때문에 (문자열이나 호출 스택이 아닌 마지막 함수 호출자 만 가져옴) 나와 같은 사람들을 위해 여기에 솔루션을 게시하고 이것이 그들에게 효과가 있기를 바랍니다.

function getCallerName(func)
{
  if (!func) return "anonymous";
  let caller = func.caller;
  if (!caller) return "anonymous";
  caller = caller.toString();
  if (!caller.trim().startsWith("function")) return "anonymous";
  return caller.substring(0, caller.indexOf("(")).replace("function","");
}


//  Example of how to use "getCallerName" function

function Hello(){
console.log("ex1  =>  " + getCallerName(Hello));
}

function Main(){
Hello();

// another example
console.log("ex3  =>  " + getCallerName(Main));
}

Main();

참고 URL : https://stackoverflow.com/questions/280389/how-do-you-find-out-the-caller-function-in-javascript

반응형