Chrome डीबगर को बंद स्थानीय चर अपरिभाषित क्यों लगता है?


167

इस कोड के साथ:

function baz() {
  var x = "foo";

  function bar() {
    debugger;
  };
  bar();
}
baz();

मुझे यह अप्रत्याशित परिणाम मिला है:

यहां छवि विवरण दर्ज करें

जब मैं कोड बदलता हूं:

function baz() {
  var x = "foo";

  function bar() {
    x;
    debugger;
  };
  bar();
}

मुझे अपेक्षित परिणाम मिले:

यहां छवि विवरण दर्ज करें

इसके अलावा, अगर evalआंतरिक फ़ंक्शन के भीतर कोई कॉल है , तो मैं अपने चर का उपयोग कर सकता हूं जैसा कि मैं करना चाहता हूं (इससे कोई फर्क नहीं पड़ता कि मैं क्या पास करता हूं eval)।

इस बीच, फ़ायरफ़ॉक्स देव उपकरण दोनों परिस्थितियों में अपेक्षित व्यवहार देते हैं।

Chrome के साथ ऐसा क्या है जो डीबगर फ़ायरफ़ॉक्स की तुलना में कम सुविधाजनक तरीके से व्यवहार करता है? मैंने कुछ समय के लिए, संस्करण 41.0.2272.43 बीटा (64-बिट) सहित और इस व्यवहार को देखा है।

क्या यह है कि क्रोम का जावास्क्रिप्ट इंजन "फलैटेंस" को कार्य करता है जब यह कर सकता है?

दिलचस्प बात यह है कि अगर मैं एक दूसरे चर को जोड़ता हूं जो आंतरिक फ़ंक्शन में संदर्भित है, तो xचर अभी भी अपरिभाषित है।

मैं समझता हूं कि एक इंटरैक्टिव डिबगर का उपयोग करते समय अक्सर गुंजाइश और चर परिभाषा के साथ quirks होते हैं, लेकिन मुझे ऐसा लगता है कि भाषा विनिर्देश के आधार पर इन quirks के लिए "सर्वश्रेष्ठ" समाधान होना चाहिए। इसलिए मैं बहुत उत्सुक हूँ अगर यह फ़ायरफ़ॉक्स की तुलना में क्रोम अनुकूलन के कारण है। और यह भी कि इन अनुकूलन को विकास के दौरान आसानी से अक्षम किया जा सकता है या नहीं (शायद देव उपकरण खुले होने पर उन्हें अक्षम होना चाहिए)।

इसके अलावा, मैं इसे ब्रेकपॉइंट के साथ-साथ debuggerस्टेटमेंट के साथ भी पुन: पेश कर सकता हूं ।


2
हो सकता है कि यह आपके लिए आपके उपयोग के लिए अन-यूज्ड वैरिएबल हो रहा हो ...
dandavis

markle976 यह कहती हुई प्रतीत होती है कि debugger;रेखा वास्तव में अंदर से नहीं बुलाई गई है bar। तो डीबगर में रुकने पर स्टैक ट्रेस देखें: क्या barस्टैकट्रेस में उल्लिखित फ़ंक्शन है? अगर मैं सही हूं, तो स्टैकट्रेस को कहना चाहिए कि यह लाइन 5 पर रुकी हुई है, लाइन 7 पर, लाइन 9 पर।
डेविड नं

मुझे नहीं लगता कि वी 8 समतल कार्यों के साथ इसका कोई लेना देना है। मुझे लगता है कि यह सिर्फ एक विचित्रता है; मुझे नहीं पता कि मैं इसे बग भी कहूंगा। मुझे लगता है कि डेविड का जवाब सबसे अधिक समझ में आता है।
markle976


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

जवाबों:


149

मुझे एक v8 समस्या रिपोर्ट मिली है, जो आप पूछ रहे हैं कि क्या है।

अब, उस मुद्दे की रिपोर्ट में जो कहा गया है उसे संक्षेप में बताने के लिए ... v8 स्टैक पर एक फ़ंक्शन या "संदर्भ" ऑब्जेक्ट में स्थानीय रूप से संग्रहीत चर को संग्रहीत कर सकता है जो ढेर पर रहता है। यह स्टैक पर स्थानीय चर को आवंटित करेगा जब तक कि फ़ंक्शन में कोई आंतरिक फ़ंक्शन नहीं होता है जो उन्हें संदर्भित करता है। यह एक अनुकूलन है । यदि कोई आंतरिक फ़ंक्शन किसी स्थानीय चर को संदर्भित करता है, तो इस चर को एक संदर्भ ऑब्जेक्ट (यानी ढेर के बजाय ढेर पर) में रखा जाएगा। का मामला evalविशेष है: यदि इसे किसी आंतरिक कार्य द्वारा बुलाया जाता है, तो सभी स्थानीय चर संदर्भ वस्तु में डाल दिए जाते हैं।

संदर्भ ऑब्जेक्ट का कारण यह है कि सामान्य तौर पर आप बाहरी एक से एक आंतरिक फ़ंक्शन को वापस कर सकते हैं और फिर जो स्टैक मौजूद था, जबकि बाहरी फ़ंक्शन नहीं चलता था। तो कुछ भी आंतरिक फ़ंक्शन एक्सेस को बाहरी फ़ंक्शन से बचने और ढेर पर रहने के बजाय ढेर पर रहना पड़ता है।

डीबगर उन वेरिएबल्स का निरीक्षण नहीं कर सकता है जो स्टैक पर हैं। डिबगिंग में आई समस्या के बारे में, एक परियोजना सदस्य कहते हैं :

एकमात्र उपाय जो मैं सोच सकता था, वह यह है कि जब भी डिवोल्ट्स चालू होंगे, हम सभी कोड को हटा देंगे और जबरन संदर्भ आवंटन के साथ फिर से जुड़ेंगे। हालांकि नाटकीय रूप से सक्षम भक्तों के साथ प्रदर्शन को पुनः प्राप्त करेंगे।

यहां "यदि कोई आंतरिक कार्य चर को संदर्भित करता है, तो इसे एक संदर्भ वस्तु में रखें" इसका एक उदाहरण है। आप चलाने यदि यह आप का उपयोग कर सकेंगे xपर debuggerबयान भले ही xकेवल में प्रयोग किया जाता है fooसमारोह, जो कभी नहीं कहा जाता है !

function baz() {
  var x = "x value";
  var z = "z value";

  function foo () {
    console.log(x);
  }

  function bar() {
    debugger;
  };

  bar();
}
baz();

13
क्या आपने कोड को अपनाने का एक तरीका निकाला है? मैं डीईआरईआर का उपयोग आरईपीएल और कोड के रूप में करना पसंद करता हूं फिर कोड को अपनी फाइलों में स्थानांतरित करता हूं। लेकिन यह अक्सर चर के रूप में संभव नहीं होता है जो कि सुलभ होना चाहिए। एक साधारण eval यह नहीं करेगा। मुझे लगता है कि लूप के लिए एक अनंत सुना जा सकता है।
रे फॉस

मैंने वास्तव में डिबगिंग करते समय इस समस्या में भाग नहीं लिया है, इसलिए मैंने कोड को अपनाने के तरीकों की खोज नहीं की है।
लुई

6
इस मुद्दे की अंतिम टिप्पणी कहती है: V8 को एक ऐसे मोड में लाना जहां सब कुछ जबरन संदर्भ के लिए आवंटित किया जाना संभव है, लेकिन मुझे यकीन नहीं है कि कैसे / कब ट्रिगर किया जाए कि Devtools UI के माध्यम से डिबगिंग के लिए, मैं कभी-कभी ऐसा करना चाहता हूं। । मैं ऐसे मोड को कैसे मजबूर कर सकता हूं?
सुमा

2
@ user208769 डुप्लिकेट के रूप में बंद होने पर, हम उस प्रश्न का पक्ष लेते हैं जो भविष्य के पाठकों के लिए सबसे उपयोगी है। ऐसे कई कारक हैं जो यह निर्धारित करने में सहायता करते हैं कि कौन सा प्रश्न सबसे अधिक उपयोगी है: आपके प्रश्न को ठीक 0 उत्तर मिले, जबकि यह एक से अधिक उत्कीर्ण उत्तर मिला। तो यह प्रश्न दो में से सबसे उपयोगी है। तिथियां केवल एक निर्धारण कारक बन जाती हैं यदि उपयोगिता ज्यादातर समान होती है।
लुइस

1
यह उत्तर वास्तविक प्रश्न (क्यों?) का उत्तर देता है, लेकिन निहित प्रश्न - मैं अपने कोड में उनके लिए अतिरिक्त संदर्भ जोड़े बिना डिबगिंग के लिए अप्रयुक्त संदर्भ चर तक कैसे पहुंच सकता हूं? - नीचे @OwnageIsMagic द्वारा बेहतर उत्तर दिया गया है।
सिगफ्रीड

30

जैसे @ लुइस ने कहा कि यह v8 अनुकूलन के कारण हुआ। जहाँ यह चर दिखाई दे रहा है, वहाँ आप कॉल स्टैक को फ्रेम में रख सकते हैं:

call1 call2

या के debuggerसाथ बदलें

eval('debugger');

eval वर्तमान हिस्सा बंद कर देंगे


1
लगभग महान! यह सामग्री के साथ एक वीएम मॉड्यूल (पीला) में रुकता है debugger, और संदर्भ वास्तव में उपलब्ध है। यदि आप उस कोड को एक स्तर तक बढ़ाते हैं जिसे आप वास्तव में डिबग करने की कोशिश कर रहे हैं, तो आप संदर्भ के लिए उपयोग नहीं कर रहे हैं। तो यह सिर्फ थोड़ा क्लूनी है, छिपे हुए क्लोजर चर को एक्सेस करते समय आप जिस कोड पर डिबगिंग कर रहे हैं, उसे देखने में सक्षम नहीं हैं। मैं अपवोट करूंगा, हालाँकि, क्योंकि यह मुझे कोड जोड़ने से बचाता है, जो स्पष्ट रूप से डिबगिंग के लिए नहीं है, और यह मुझे पूरे ऐप को डीटॉमीफाई किए बिना पूरे संदर्भ तक पहुंच देता है।
Sigfried

ओह ... यह evalसंदर्भ तक पहुंच पाने के लिए पीले एड सोर्स विंडो का उपयोग करने की तुलना में भी अधिक क्लिंकर है : आप कोड के माध्यम से कदम नहीं उठा सकते हैं (जब तक कि आप eval('debugger')उन सभी लाइनों के बीच नहीं डालते हैं जहां से आप कदम रखना चाहते हैं।)
सिगफ्रीड

ऐसा लगता है कि ऐसी परिस्थितियाँ हैं, जहाँ उपयुक्त स्टैक फ्रेम में ट्रावर्स करने के बाद भी कुछ चर अदृश्य होते हैं; मेरे पास कुछ है controllers.forEach(c => c.update())और एक ब्रेकपॉइंट को अंदर गहराई से मारा c.update()। यदि मैं तब उस फ़्रेम का चयन करता हूं controllers.forEach(), जहां कहा जाता है, controllersतो अपरिभाषित है (लेकिन उस फ्रेम में बाकी सब कुछ दिखाई देता है)। मैं एक न्यूनतम संस्करण के साथ पुन: पेश नहीं कर सका, मुझे लगता है कि जटिलता की कुछ सीमा हो सकती है जिसे पारित करने की आवश्यकता है या कुछ और।
पीटरटी

@PeterT अगर यह होता है <अपरिभाषित> आप गलत जगह पर हैं या somewhere deep inside c.update()अपने कोड async चला जाता है और आप async स्टैक फ्रेम को देखने
OwnageIsMagic

6

मैंने इसे नोडज में भी देखा है। मेरा मानना ​​है (और मैं मानता हूं कि यह केवल एक अनुमान है) कि जब कोड संकलित किया जाता है, अगर xअंदर प्रकट नहीं होता है bar, तो यह इसके xदायरे में उपलब्ध नहीं करता है bar। यह शायद इसे थोड़ा अधिक कुशल बनाता है; समस्या यह है कि कोई भूल गया (या ध्यान नहीं दिया) कि यहां तक ​​कि अगर वहाँ नहीं xहै bar, तो आप डिबगर चलाने का फैसला कर सकते हैं और इसलिए अभी भी xअंदर से पहुंचने की आवश्यकता है bar


3
धन्यवाद। मूल रूप से मैं जावास्क्रिप्ट शुरुआती को "डिबगर झूठ" से बेहतर व्याख्या करने में सक्षम होना चाहता हूं।
गाबे कोपले

@GabeKopley: तकनीकी रूप से डिबगर झूठ नहीं बोल रहा है। यदि एक चर को संदर्भित नहीं किया जाता है, तो यह तकनीकी रूप से संलग्न नहीं है। इस प्रकार क्लोजर बनाने के लिए दुभाषिया की कोई आवश्यकता नहीं है।
स्लीवतमैन

7
ये मुद्दा नहीं है। डिबगर का उपयोग करते समय, मैं अक्सर ऐसी स्थिति में रहा हूं जहां मैं एक बाहरी दायरे में एक चर के मूल्य को जानना चाहता था, लेकिन इस वजह से नहीं कर सका। और अधिक दार्शनिक नोट पर, मैं कहूंगा कि डिबगर झूठ बोल रहा है। क्या आंतरिक दायरे में मौजूद चर इस बात पर निर्भर नहीं होना चाहिए कि क्या यह वास्तव में उपयोग किया गया है या क्या कोई असंबंधित evalआदेश है। यदि चर घोषित किया जाता है, तो यह सुलभ होना चाहिए।
डेविड नाइप

2

वाह, वाकई दिलचस्प!

जैसा कि दूसरों ने उल्लेख किया है, ऐसा लगता है कि संबंधित है scope, लेकिन अधिक विशेष रूप से, से संबंधित है debugger scope। जब डेवलपर स्क्रिप्ट का मूल्यांकन डेवलपर टूल में किया जाता है, तो यह निर्धारित करने के लिए लगता है ScopeChain, जिसके परिणामस्वरूप कुछ विचित्रता होती है (क्योंकि यह इंस्पेक्टर / डीबगर स्कोप के लिए बाध्य है)। आपके द्वारा पोस्ट की गई एक भिन्नता यह है:

(संपादित करें - वास्तव में, आप अपने मूल प्रश्न में इसका उल्लेख करते हैं, हाँ , मेरा बुरा! )

function foo() {
  var x = "bat";
  var y = "man";

  function bar() {
    console.log(x); // logs "bat"

    debugger; // Attempting to access "y" throws the following
              // Uncaught ReferenceError: y is not defined
              // However, x is available in the scopeChain. Weird!
  }
  bar();
}
foo();

महत्वाकांक्षी और / या जिज्ञासु के लिए, गुंजाइश (हेह) स्रोत को देखने के लिए कि क्या चल रहा है:

https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger


0

मुझे संदेह है कि यह परिवर्तनशील और फंक्शन उत्थापन के साथ करना है। जावास्क्रिप्ट यहाँ समारोह वे में परिभाषित कर रहे हैं के शीर्ष करने के लिए सभी चर और समारोह घोषणाओं लाता है और जानकारी:। Http://jamesallardice.com/explaining-function-and-variable-hoisting-in-javascript/

मैं शर्त लगाता हूं कि क्रोम विराम के साथ ब्रेक पॉइंट को गुंजाइश के लिए अनुपलब्ध है क्योंकि फ़ंक्शन में कुछ और नहीं है। यह काम करने लगता है:

function baz() {
  var x = "foo";

  function bar() {
    console.log(x); 
    debugger;
  };
  bar();
}

जैसा कि यह है:

function baz() {
  var x = "foo";

  function bar() {
    debugger;
    console.log(x);     
  };
  bar();
}

उम्मीद है कि, और / या ऊपर दिए गए लिंक से मदद मिलती है। ये मेरे पसंदीदा प्रकार के SO प्रश्न हैं, BTW :)


धन्यवाद! :) मैं सोच रहा हूं कि एफएफ अलग क्या करता है। एक डेवलपर के रूप में मेरे नजरिए से, एफएफ का अनुभव निष्पक्ष रूप से बेहतर है ...
गाबे कोपले

2
"लेक्स टाइम पर ब्रेक पॉइंट को कॉल करना" मुझे संदेह है। यही कारण है कि ब्रेकप्वाइंट नहीं हैं। और मैं यह नहीं देखता कि समारोह में अन्य चीजों की अनुपस्थिति क्यों मायने रखती है। कहा जा रहा है कि, अगर यह नोडज की तरह कुछ भी है तो ब्रेकप्वाइंट बहुत छोटी गाड़ी हो सकती है।
डेविड नं
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.