javascript - आप जावास्क्रिप्ट में कॉलर फ़ंक्शन कैसे ढूंढते हैं?




callstack (19)

स्टैक ट्रेस

आप ब्राउजर विशिष्ट कोड का उपयोग कर पूरे स्टैक ट्रेस पा सकते हैं। अच्छी बात यह है कि किसी ने इसे पहले ही बनाया है ; गिटहब पर प्रोजेक्ट कोड यहां है।

लेकिन सभी खबर अच्छी नहीं है:

  1. स्टैक ट्रेस प्राप्त करना वाकई धीमा है इसलिए सावधान रहें ( this और पढ़ें)।

  2. आपको स्टैक ट्रेस के लिए फ़ंक्शन नाम परिभाषित करने की आवश्यकता होगी। क्योंकि अगर आपके पास ऐसा कोड है:

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

    Google क्रोम चेतावनी देगा ... kls.Hello ( ... लेकिन अधिकांश ब्राउज़र कीवर्ड function ठीक बाद फ़ंक्शन नाम की अपेक्षा करेंगे और इसे अज्ञात फ़ंक्शन के रूप में देखेंगे। यदि आप क्रोम Klass नाम का उपयोग नहीं कर पाएंगे तो भी समारोह में kls नाम नहीं दें।

    और वैसे, आप फ़ंक्शन प्रिंटस्टैकट्रेस विकल्प {guess: true} लेकिन मुझे ऐसा करके कोई वास्तविक सुधार नहीं मिला।

  3. सभी ब्राउज़र आपको एक ही जानकारी नहीं देते हैं। यही है, पैरामीटर, कोड कॉलम, आदि

कॉलर समारोह का नाम

वैसे, अगर आप केवल कॉलर फ़ंक्शन का नाम चाहते हैं (अधिकांश ब्राउज़रों में, लेकिन IE नहीं) तो आप इसका उपयोग कर सकते हैं:

arguments.callee.caller.name

लेकिन ध्यान दें कि यह नाम function कीवर्ड के बाद एक होगा। पूरे समारोह के कोड प्राप्त किए बिना उससे अधिक पाने के लिए मुझे कोई रास्ता नहीं मिला (यहां तक ​​कि Google क्रोम पर भी)।

कॉलर फंक्शन कोड

और बाकी के सर्वोत्तम उत्तरों को सारांशित करना (पाब्लो कैबरेरा, नॉर्डिन और ग्रेग हेगिल द्वारा)। एकमात्र क्रॉस-ब्राउज़र और वास्तव में सुरक्षित चीज़ जिसका आप उपयोग कर सकते हैं:

arguments.callee.caller.toString();

जो कॉलर फ़ंक्शन का कोड दिखाएगा। अफसोस की बात है, यह मेरे लिए पर्याप्त नहीं है, और इसलिए मैं आपको स्टैकट्रेस और कॉलर फ़ंक्शन नाम के लिए सुझाव देता हूं (हालांकि वे क्रॉस-ब्राउज़र नहीं हैं)।

function main()
{
   Hello();
}

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

कॉल स्टैक को खोजने का कोई तरीका है?


2018 से एक संदेश जहां caller तक पहुंच प्रतिबंधित है:

निम्न कार्य फ़ायरफ़ॉक्स 52 और क्रोम 61 में नौकरी करने के लिए प्रतीत होता है हालांकि इसके कार्यान्वयन में दो ब्राउज़रों के लॉगिंग प्रारूप के बारे में बहुत सारी धारणाएं होती हैं और किसी भी अस्थायी डेवलपर डीबगिंग के लिए इसका उपयोग नहीं किया जाना चाहिए क्योंकि यह अपवाद फेंकता है और संभवतः दो निष्पादित करता है किया जाने से पहले regex मिलान।

let fnNameMatcher = /([^(]+)@|at ([^(]+) \(/;

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

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

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

इस समस्या के आसपास एक और तरीका कॉलम फ़ंक्शन का नाम पैरामीटर के रूप में पास करना है।

उदाहरण के लिए:

function reformatString(string, callerName) {

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

    return string;
}

अब, आप इस तरह के फ़ंक्शन को कॉल कर सकते हैं:

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

    reformatString(myString, function.name);
}

मेरा उदाहरण फ़ंक्शन नाम की हार्ड कोडेड चेक का उपयोग करता है, लेकिन आप वहां जो भी चाहते हैं उसे करने के लिए आसानी से स्विच स्टेटमेंट या कुछ अन्य तर्क का उपयोग कर सकते हैं।


इसे एक्सेस करने का प्रयास करें:

arguments.callee.caller.name

ऐसा लगता है कि यह काफी हल प्रश्न है लेकिन मुझे हाल ही में पता चला है कि developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… इसलिए मेरे अपने उपयोग के लिए मैंने एक कक्षा लिखी है जिसे इसे कहां से जाना जाता है। यह एक छोटे से सहायक lib का हिस्सा है और यदि आप कोड स्टैंडअलोन का उपयोग करना चाहते हैं तो ऑफसेट को कॉलर के स्टैक ट्रेस को वापस करने के लिए उपयोग किया जाता है (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('.');
  };
}

कॉलिंग फ़ंक्शन पाने के लिए आप फंक्शन.केलर का उपयोग कर सकते हैं। Argument.caller का उपयोग करने वाली पुरानी विधि अप्रचलित मानी जाती है।

निम्नलिखित कोड इसके उपयोग को दर्शाता है:

function Hello() { return Hello.caller;}

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

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

अप्रचलित तर्क.caller के बारे में नोट्स: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/caller

सावधान रहें Function.caller गैर मानक है: Function.caller


निम्नलिखित कोड आज़माएं:

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

फ़ायरफ़ॉक्स -21 और क्रोमियम -25 में मेरे लिए काम किया।


बस अपनी त्रुटि स्टैक लॉग इन कंसोल करें। तब आप जान सकते हैं कि आपको कैसे बुलाया जा रहा है

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

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

sello()


मुझे पता है कि आपने "जावास्क्रिप्ट में" उल्लेख किया है, लेकिन यदि उद्देश्य डिबगिंग है, तो मुझे लगता है कि बस अपने ब्राउज़र के डेवलपर टूल का उपयोग करना आसान है। क्रोम में यह कैसा दिखता है: बस डीबगर ड्रॉप करें जहां आप ढेर की जांच करना चाहते हैं।


मुझे लगता है कि निम्नलिखित कोड टुकड़ा सहायक हो सकता है:

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

मैं इस प्रश्न के साथ दोनों प्रश्न और वर्तमान बक्षीस को संबोधित करने का प्रयास कर रहा हूं।

बक्षीस की आवश्यकता है कि कॉलर सख्त मोड में प्राप्त किया जाए, और एकमात्र तरीका जिसे मैं इसे देख सकता हूं वह सख्त मोड के बाहर घोषित फ़ंक्शन का जिक्र कर रहा है।

उदाहरण के लिए, निम्नलिखित गैर-मानक है लेकिन क्रोम, एज और फ़ायरफ़ॉक्स के वर्तमान (2 9/03/2016) संस्करणों के साथ परीक्षण किया गया है:

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

मैं इसके लिए यहां अपना बेवकूफ जोड़ना चाहता था:

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

मैंने परीक्षण किया यह क्रोम, सफारी और आईई (10 और 8) है। ठीक काम करता है। केवल 1 कार्य है जो मायने रखता है, इसलिए यदि आप बड़े पहेली से डरते हैं, तो नीचे पढ़ें।

नोट: इस पहेली में मेरे अपने "बॉयलरप्लेट" की उचित मात्रा है। यदि आप चाहें तो आप इसे हटा सकते हैं और विभाजन का उपयोग कर सकते हैं। यह केवल एक अल्ट्रा-सुरक्षित "कार्यों का सेट है जिस पर मैं भरोसा करता हूं।

वहां एक "जेएसफ़िल्ड" टेम्पलेट भी है जो मैं कई पहेलियों के लिए उपयोग करता हूं ताकि जल्दी से झुकाव हो सके।


यदि आप IE में इसे चलाने के लिए नहीं जा रहे हैं <11 तो console.trace() सूट होगा।

function main() {
    Hello();
}

function Hello() {
    console.trace()
}

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

यदि आप केवल फ़ंक्शन का नाम चाहते हैं और कोड नहीं चाहते हैं, और ब्राउज़र-स्वतंत्र समाधान चाहते हैं, तो निम्न का उपयोग करें:

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

यहां, caller.toString() सब कुछ caller.toString() साथ 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 Hello() {
    alert("caller is " + arguments.callee.caller.toString());
}

इसके बराबर है:

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

जाहिर है कि पहला बिट अधिक पोर्टेबल है, क्योंकि आप फ़ंक्शन का नाम बदल सकते हैं, "हैलो" से "सीओओ" से कहें, और अभी भी पूरी चीज को काम करने के लिए मिलता है।

बाद में, यदि आप आवंटित फ़ंक्शन (हैलो) के नाम को दोबारा करने का निर्णय लेते हैं, तो आपको इसकी सभी घटनाओं को बदलना होगा :(


Arguments.caller बहिष्कृत होने के बाद से *arguments.callee.caller का उपयोग करना सुरक्षित है ...


हेस्टवार्ट के जवाब और जियारॉन्गू के जवाब दोनों ने उल्लेख किया कि 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: [email protected]://stacksnippets.net/js:14:8 Firefox : Caller is: [email protected]://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 साथ स्टैक सेट करेंगे var stack = (new Error()).stack । इंटरनेट एक्सप्लोरर में स्टैक को अपरिभाषित किया जाएगा - आपको स्टैक को पुनर्प्राप्त करने के लिए एक वास्तविक अपवाद फेंकना होगा।

निष्कर्ष: Error ऑब्जेक्ट में stack का उपयोग करके "मुख्य" कॉलर "हैलो" को निर्धारित करना संभव है। वास्तव में यह उन मामलों में काम करेगा जहां callee / caller दृष्टिकोण काम नहीं करता है। यह आपको संदर्भ, यानी स्रोत फ़ाइल और लाइन नंबर भी दिखाएगा। हालांकि समाधान क्रॉस प्लेटफार्म बनाने के लिए प्रयास की आवश्यकता है।


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





callstack