Schnelle Suche nach der Quelle unerwünschter Mutationen einer Objekteigenschaft

Hallo! Heute werde ich Ihnen erklären, wie Sie mit dem Debugger meines Erachtens ein nicht triviales JavaScript-Problem lösen können.

In JavaScript sind Objekte ein zusammengesetzter Datentyp, dessen Wert als Referenz übergeben wird. Mit anderen Worten, wenn wir ein Objekt als Parameter an eine Funktion übergeben oder an einer beliebigen Stelle, an der wir seine Eigenschaften ändern können. Verwenden einer Anweisung, die aus einem variablen Ausdruck besteht, in dem ein Link sowie Punkt- und Zuweisungsoperatoren gespeichert sind. Danach erhalten andere Anweisungen, die mit dieser Variablen / diesem Parameter arbeiten oder arbeiten werden, eine Eigenschaftsänderung durch Verweis.

Häufig verfälscht dieses Verhalten Benutzerdaten, führt zu Fehlern und ist unerwünscht.

Das Auffinden der Ursache für solche unerwünschten Eigenschaftsänderungen kann lange dauern: Das Programm kann also bereits umfangreich sein und aus Hunderttausenden von Anweisungen bestehen.

Schauen wir uns ein einfaches Beispiel an.

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Debug property mutation example</title> <script> const user = { firstName: 'Vasilij', middleName: 'Alibabaevich', lastName: 'Radner', aka: 'Alibaba', getFullName() { return `${this.lastName} ${this.firstName.slice(0, 1)}. ${this.middleName.slice(0, 1)}.` } }; </script> <script src="object-property-mutation.js" type="application/javascript"></script> </head> </head> <body> <script> Promise.resolve(user).then(user.getFullName.bind(user)).then(console.log); </script> </body> </html> 

Jetzt funktioniert das Webprogramm nicht mehr, da in der Konsole ein Fehler vorliegt und der vollständige Name nicht ausgegeben wird.

Bild

Wir lesen die oberste Nachricht in der Konsole:

 Uncaught (in promise) TypeError: Cannot read property 'slice' of undefined 

Ein Fehler wie: wurde nicht verarbeitet (als Versprechen): Ich kann die Slice-Eigenschaft nicht von undefined lesen.

Klicken Sie auf den Link und gehen Sie zur Fehlerstelle.

 getFullName() { return `${this.lastName} ${this.firstName.slice(0, 1)}. ${this.middleName.slice(0, 1)}.` } 

Wir sehen, dass der falsche Ausdruck
 this.firstName.slice(0, 1) 
besteht aus vier Operatoren:

  1. zwei Punktoperatoren
  2. ein Komma-Trennzeichen
  3. Ein Gruppierungsoperator - ein Paar Klammern

Lesen wir die Anweisungen. Der linke Ausdruck wird zuerst ausgewertet

 this.firstName 

Es besteht aus einem Punktoperator, links dem primären Ausdruck und rechts dem Bezeichner firstName. Das Ergebnis dieses Ausdrucks ist undefiniert. Das Ausführen der folgenden Punktanweisung verursacht einen Fehler. Da der Punktoperator nur mit Objekttypen arbeitet, führt seine Ausführung von undefined zu einem Fehler - ich kann die Slice-Eigenschaft nicht von undefined erhalten.

Es stellt sich heraus, dass diese Eigenschaft irgendwo auf undefiniert gesetzt wurde ...

Um dieses Problem zu lösen, versuchen wir das Gegenteil. Wir werden das Debug-Tool verwenden, um die Ausnahme zu stoppen . Verschieben wir den Aufruf-Stack von der Fehlerstelle aus nach unten, versuchen wir, mit der Anweisung fortzufahren, die die Eigenschaft geändert hat.

Wählen Sie das Ausnahmestopp-Tool aus


Bild

Wir sehen, dass es nur zwei Aufrufe im Stapel gibt. Zum vorherigen Anruf wechseln.

Bild

Wir sehen, dass es keine explizite Anweisung gibt, die die firstName-Eigenschaft ändert.

Bild

Wir schließen daraus, dass die Änderung in diesem Aufrufstapel nicht auftritt.

Wie findest du das


Und wie finde ich den Bösewicht, der das Eigentum meines Objekts geändert hat?

Bitte schreiben Sie in die Kommentare, wie würden Sie es finden?
Leute, die mit mir arbeiten und denen ich es dir gesagt habe, schreibe bitte einen Stern in den Kommentar.

Es interessiert mich sehr, wie andere JavaScript-Spezialisten solche Probleme lösen.

Wissen Sie, als ich zum ersten Mal auf dieses JavaScript-Verhalten gestoßen bin, habe ich ein paar Stunden damit verbracht, ein Haarbüschel von meinem Pony zu untersuchen und abzureißen ...

Deaktivieren Sie das Pausentool in Ausnahmefällen.

Also, hier ist unser neuer Plan, wir werden die firstName-Eigenschaft im Benutzerobjekt mit dem Getter und Setter definieren.

Wir fügen dem Setter die Debug-Anweisung hinzu, indem wir die Debugger-Anweisung und die Semikolon-Anweisung verwenden.

 const user = { _firstName: 'Vasilij', set firstName(value) { debugger; this._firstName = value; }, get firstName() {return this._firstName}, middleName: 'Alibabaevich', lastName: 'Radner', aka: 'Alibaba', getFullName() { return `${this.lastName} ${this.firstName.slice(0, 1)}. ${this.middleName.slice(0, 1)}.`; } }; 

Wenn Sie den Aufrufstapel weiter durchlaufen, finden Sie eine Anweisung, die die Eigenschaft firstName ändert.

Der Debugger wurde im Setter angehalten, bevor der neue Wert in das Objekt geschrieben wurde.

Bild

Wir sehen, dass der Wert des Parameterwerts undefiniert ist.

Mit dem Aufrufstapel können wir jetzt problemlos zum vorherigen Aufruf wechseln.

Bild

iiiii, Sieg aaaaaah.

Es gibt eine noch einfachere Möglichkeit, dieses Problem zu lösen, indem Sie das Debugging-Tool verwenden , das ausnahmsweise stoppt .

Hier ist unser neuer Plan: Lassen Sie uns das Benutzerobjekt nicht zum Objekt machen und mit dem Stop-by-Exception- Tool leicht zur fehlerhaften Anweisung gelangen.

Da wir wissen, dass beim Versuch, eine Eigenschaft von undefined abzurufen, ein Fehler auftritt.

Wir schalten das Exception Stop Tool ein, setzen die Benutzervariable auf undefined.

  const user = undefined; 

Wir hielten wieder an der Stelle an, an der die Eigenschaft firstName verzerrt war.

Bild

Das ist alles, was ich Ihnen heute über das Debuggen unerwünschter Änderungen an Objekten erzählen wollte.

Vielen Dank für das Lesen des Artikels. Abonnieren Sie den Kanal und teilen Sie dieses Video und den Artikel mit Freunden. Alles Gute.

github.com/NVBespalov/js-lessons/tree/error/property-mutation

Source: https://habr.com/ru/post/de481824/


All Articles