Warum macht Chrome-debugger denke geschlossenen lokalen variable nicht definiert ist?
Mit diesem code:
function baz() {
var x = "foo";
function bar() {
debugger;
};
bar();
}
baz();
Komme ich zu diesem unerwarteten Ergebnis:
Wenn ich den code ändern:
function baz() {
var x = "foo";
function bar() {
x;
debugger;
};
bar();
}
Bekomme ich das erwartete Ergebnis:
Auch, wenn es keinen Aufruf zu eval
innerhalb der inneren Funktion, ich kann auf meine variable, die ich tun will (egal was ich pass auf eval
).
Mittlerweile Firefox-dev-tools geben, die das erwartete Verhalten in beiden Fällen.
Was ist mit Chrome, dass der debugger verhält sich weniger günstig als Firefox? Ich habe beobachtet, dieses Verhalten für einige Zeit, bis zu und einschließlich der Version 41.0.2272.43 beta (64-bit).
Ist es, dass die Chrome-javascript-engine "verflacht" die Funktionen aus, wenn Sie es können?
Interessanterweise, wenn ich, fügen Sie eine zweite variable, die ist verwiesen, in der die innere Funktion, die x
variable ist noch nicht definiert.
Ich verstehen, dass es oft Macken mit scope und Variablen definition bei Verwendung eines interaktiven debugger, aber es scheint mir, dass auf der Grundlage der Sprach-Spezifikation soll es eine "beste" Lösung für diese Macken. Also ich bin sehr gespannt, ob dies aufgrund der Chrome-Optimierung weiter als Firefox. Und auch, ob oder nicht diese Optimierungen können problemlos deaktiviert werden, während der Entwicklung (vielleicht sollten Sie deaktiviert werden, wenn die dev tools öffnen?).
Ich auch reproduzieren können, das mit den breakpoints sowie die debugger
- Anweisung.
markle976 scheint zu sagen die
debugger;
Linie ist nicht eigentlich als von innen bar
. So suchen Sie in der Stapel-Ablaufverfolgung, wenn es Pausen im debugger: Ist die bar
Funktion erwähnt, in der stacktrace? Wenn ich Recht habe, dann ist der stacktrace sollte sagen, es ist Pause an Linie 5, Linie 7, Linie 9.Ich glaube nicht, dass es nichts zu tun hat mit V8 Abflachung Funktionen. Ich denke, das ist nur eine Macke; ich weiß nicht, ob ich würde sogar sagen ein bug. Ich denke, dass David die Antwort von unten am meisten Sinn macht.
siehe auch garbage-collection, mit node.js, Wie sind Schließungen und Bereiche dargestellt, die zur Laufzeit in JavaScript und Über Verschluss, LexicalEnvironment und GC
Ich habe das gleiche Problem, ich hasse es. Aber wenn ich zugreifen müssen, Verschluss-Einträge in der Konsole, ich gehe dorthin, wo Sie sehen können, den Anwendungsbereich, finden die Closure Eintrag aus und öffnen Sie es. Dann mit der rechten Maustaste auf das element, das Sie brauchen, und klicken Sie auf Speichern als Globale Variable. Eine neue Globale variable
temp1
wird an der Konsole und Sie können es verwenden, um Zugriff auf das scope-Eintrag.
InformationsquelleAutor Gabe Kopley | 2015-02-07
Du musst angemeldet sein, um einen Kommentar abzugeben.
Habe ich gefunden, v8 Problem melden was genau das ist, was Sie gefragt haben.
Nun, Um zusammenzufassen, was gesagt wird, in dieser Sache berichten... v8-speichern kann, die lokalen Variablen einer Funktion auf dem stack oder in ein "context" - Objekt, das Leben auf dem heap. Es wird allokieren der lokalen Variablen auf dem stack so lange, wie die Funktion enthält keine innere-Funktion, die auf Sie verweist. Es ist eine Optimierung. Wenn alle innere Funktion bezieht sich auf eine lokale variable, diese variable wird in einer Kontext-Objekt (d.h. auf dem heap statt auf dem stack). Der Fall von
eval
ist das Besondere: wenn es heißt alle, die durch eine innere Funktion alle lokalen Variablen in den Kontext-Objekt.Den Grund für das context-Objekt ist, dass im Allgemeinen Sie zurückkehren konnten, eine innere Funktion, die äußere und dann die Stapel, die existierte, während die äußere Funktion lief nicht mehr verfügbar sein. Also alles, was die innere Funktion zugreift, hat zum überleben der äußeren Funktion und live auf dem heap statt auf dem stack.
Den debugger nicht kontrollieren kann, die Variablen werden auf den stack. Im Hinblick auf das problem gestoßen, beim Debuggen, ein Projekt-Mitglied sagt:
Hier ist ein Beispiel für die "wenn jeder innere Funktion bezieht sich auf die variable, legen Sie es in einem Kontext-Objekt". Wenn Sie diese ausführen, werden in der Lage sein, um Zugriff
x
amdebugger
- Anweisung, obwohlx
ist nur in derfoo
Funktion die nie genannt!Ich habe eigentlich nicht dieses problem beim Debuggen, also ich habe nicht nach Möglichkeiten gesucht, um deopt code.
Der Letzte Kommentar aus der Ausgabe sagt: Setzen V8 in einen Modus, wo alles gewaltsam Kontext zugeordnet ist möglich, aber ich bin mir nicht sicher, wie/Wann auslösen, die durch Devtools UI Für den Willen des debugging, würde ich mal so tun wollen. Wie kann ich die Kraft solcher Modus?
Für die Zukunft, diese Frage ist die doppelte.
Beim schließen als Duplikat, wir bevorzugen die Frage, die die meisten nützlich, um zukünftigen Lesern. Es gibt mehrere Faktoren, die helfen, festzustellen, welche Frage ist sehr nützlich: Ihre Frage habe genau 0 Antworten, während dieser man hat mehrere Antworten von Ihnen positiv bewertet werden. Also diese Frage ist nützlich, die meisten der zwei. Termine zum entscheidenden Faktor nur dann, wenn der nutzen ist meist gleich.
InformationsquelleAutor Louis
Wie @Louis sagte, dass es, verursacht durch die v8-Optimierungen.
Sie durchqueren kann Call stack frame, in dem diese variable ist sichtbar:
Oder ersetzen
debugger
miteval
wird deopt aktuellen chunkdebugger
, und der Zusammenhang ist ja vorhanden. Wenn Sie Schritt bis der Stapel eine Ebene mit der code, den Sie sind tatsächlich versucht, zu Debuggen, Sie sind zurück, um nicht den Zugang zum Kontext. So ist es nur etwas klobig, die nicht in der Lage, Blick auf den code, den Sie Debuggen sind beim Zugriff auf versteckte Schließung Variablen. Ich werde upvote, obwohl, da es spart mir aus mit code hinzufügen, der ist offensichtlich nicht für das Debuggen und es gibt mir Zugang zur gesamten Kontext ohne deoptimizing die ganze app.Oh...es ist sogar clunkier, als die gelben
eval
ed-source-Fenster, um Zugriff zum Kontext: man kann nicht schrittweise durch den code (es sei denn, Sie setzeneval('debugger')
zwischen all den Zeilen, die Sie wollen, um Schritt über.)Es scheint, dass es Situationen gibt, in denen bestimmte Variablen sind nicht sichtbar, obwohl nach der Durchquerung der entsprechenden stack-frame; ich habe so etwas wie
controllers.forEach(c => c.update())
und einen Haltepunkt erreicht haben irgendwo, tief inc.update()
. Wenn ich dann wählen Sie den Rahmen, wocontrollers.forEach()
genannt wird,controllers
undefiniert (aber sonst alles im Rahmen ist sichtbar). Ich konnte das nicht reproduzieren mit einer minimalen version, ich nehme an, es kann eine Schwelle der Komplexität, die übergeben werden muss oder so etwas.wenn es <undefined> Sie sind in der falschen Ort Oder
somewhere deep inside c.update()
code geht async und Sie sehen, async stack frameInformationsquelleAutor OwnageIsMagic
Ich habe auch bemerkt, dass diese in nodejs. Ich glaube (und ich gebe zu, das ist nur eine Vermutung), dass wenn der code kompiliert wird, wenn
x
nicht erscheinen inbar
es nicht machenx
verfügbar innerhalb des Bereichs vonbar
. Dies macht es wahrscheinlich etwas effizienter; das problem ist, jemand vergessen (oder nicht-Pflege) , selbst wenn es keinenx
imbar
Sie entscheiden könnten, um den debugger auszuführen und somit noch brauchen, um Zugangx
von innenbar
.Technisch ist der debugger nicht Lügen. Wenn eine variable nicht verwiesen wird, dann ist es technisch nicht eingeschlossen. So gibt es keine Notwendigkeit für den interpreter zu erstellen, die Schließung.
Das ist nicht der Punkt. Bei der Verwendung von debugger habe ich Häufig in einer situation, wo ich wollte wissen, den Wert einer Variablen in einem äußeren Rahmen, konnte aber nicht, weil dieser. Und auf eine philosophische Bemerkung, ich würde sagen, der debugger liegt. Ob die variable existiert in den inneren Rahmen sollte nicht davon abhängen, ob es ' s tatsächlich verwendet werden oder ob es eine unabhängige
eval
Befehl. Wenn die variable deklariert ist, zugänglich sein sollte.InformationsquelleAutor David Knipe
Wow, wirklich interessant!
Wie andere erwähnt haben, dies scheint zurückzuführen zu sein
scope
, aber mehr speziell, im Zusammenhang mitdebugger scope
. Wenn injiziert-Skript ausgewertet wird in der Entwickler-tools, so scheint es, um zu bestimmen, eineScopeChain
, die Ergebnisse in einigen Marotten (denn es ist gebunden an die Inspektor/debugger-Bereich). Eine variation von dem, was du gepostet hast, ist dieses:(EDIT - tatsächlich, Sie erwähnen diese in Ihrer ursprünglichen Frage, igitt, ist mir schlecht!)
Für den ambitionierten und/oder neugierig, Geltungsbereich (heh), die Quelle, um zu sehen, was Los ist:
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/inspector
https://github.com/WebKit/webkit/tree/master/Source/JavaScriptCore/debugger
InformationsquelleAutor Jack