Statische JavaScript-Parser und Fehler, aus denen sie beim Verlernen helfen (Teil 2)

Ursprünglicher Autor: Zack Grossbart
  • Übersetzung
Wir setzen die Übersetzung des Artikels über statische Analysatoren fort: Im letzten Teil ging der Autor auf Nuancen wie die Verwendung von == und === Operatoren sowie auf unbestimmte Variablen und späte Definitionen ein. Außerdem weist der Autor auf die Kommentare hin, die die Analysatoren (anhand des JSHint-Beispiels) geben Erkennen solcher Fehler. In diesem Teil werden wir uns mit der Neudeklaration einer Variablen sowie der Steuerung der zyklomatischen Komplexität des Codes befassen.


Erneutes Deklarieren (Verwenden) einer Variablen
In JavaScript können Sie Variablen erneut deklarieren (verwenden). Dies geschieht jedoch fast immer aus Versehen. Siehe:

function incrementCount(counter) {
 if (counter.count) {
  counter.count++;
 } else {
  var counter = 1;
  counter.count = counter;
 }
}


In dieser Funktion erhöhen wir die count-Eigenschaft für das präsentierte Objekt, müssen die Eigenschaft jedoch hinzufügen, wenn sie noch nicht vorhanden ist. Den Bug sehen?

Diese Funktion fügt niemals einen Zähler hinzu oder erhöht ihn. Der Ausdruck else wird immer aufgerufen und definiert das Argument für die Zählerfunktion neu. Grundsätzlich erstellt diese Funktion ein neues Objekt, weist ihm eine Eigenschaft zu und verliert das Objekt, wenn die Funktion zurückkehrt. Sie ändert niemals das präsentierte Objekt.

Mit diesem einfachen Typ können Sie den Code fehlerfrei ausführen, was jedoch zu einem merkwürdigen Ergebnis führt.

JSHint zeigt Folgendes:

test.js: line 21, col 21, 'counter' is already defined.


Klammern in Blöcken, Schleifen und bedingten Konstruktionen

if (false)
 doSomethingElse();
 doSomething();


Was wird dieser Code tun - doSomething oder doSomethingElse? Auf den ersten Blick scheint es mir immer so, als würde er weder doSomething noch doSomethingElse ausführen. So funktioniert das in Python, aber nicht in JavaScript. JavaScript führt zunächst die Zeile unter der if-Anweisung als Teil des Blocks aus. Einrückung spielt keine Rolle.

Das ganze Problem ist die Lesbarkeit des Codes. Wenn Sie nicht verstehen, was der Code bewirkt, werden Sie Fehler schreiben.
Python und CoffeeScript lieben es, geschweifte Klammern zu überspringen. Dies funktioniert gut in Sprachen, die Formatierung mit freiem Speicherplatz verwenden, aber JavaScript verhält sich anders. Mit JavaScript können Sie eine große Anzahl von seltsamen Syntaxen erstellen, während geschweifte Klammern helfen, Probleme zu vermeiden.

if (false) {
 doSomethingElse();
 doSomething();
}


Wenn Sie Klammern hinzufügen, wird Ihr Code immer besser lesbar sein. Überspringen Sie sie und JSHint zeigt Ihnen Folgendes:

test.js: line 27, col 5, Expected '{' and instead saw 'doSomething'.


Einfache und doppelte Anführungszeichen

console.log("This is a string. It's OK.");
console.log('This string is OK too.');
console.log("This string " + 'is legal, but' + "really not OK.");


Mit JavaScript können Sie Zeichenfolgen mit einfachen und doppelten Anführungszeichen definieren. Dies ist gut, wenn Sie über Flexibilität verfügen, z. B. bei der Definition von HTML. Zusätzliche Flexibilität kann jedoch zu sehr inkonsistentem Code führen.

Google verfügt über einen Code-Style-Guide, der für Zeichenfolgen immer einfache Anführungszeichen verwendet, sodass doppelte Anführungszeichen in HTML nicht entfernt werden müssen. Ich kann nicht argumentieren, dass einfache Anführungszeichen besser sind als doppelte Anführungszeichen, aber ich kann argumentieren, dass Konsistenz hier wichtig ist. Compliance verbessert die Lesbarkeit von Code.

JSHint warnt Sie vor dem Mischen von Anführungszeichen wie folgt:

test.js: line 31, col 27, Mixed double and single quotes.


Falsches Kopieren und Einfügen oder Schreiben von Anführungszeichen ist ganz einfach. Sobald Sie die falschen Anführungszeichen setzen, beginnt auch der Rest damit, insbesondere wenn mehrere Personen die Datei bearbeiten. Statische Analysegeräte sorgen für konsistente Anführungszeichen und helfen, große Aufräumarbeiten in Zukunft zu vermeiden.

Zyklomatische Komplexität Die

zyklomatische Komplexität ist ein Maß für die Komplexität eines bestimmten Codeblocks. Schauen Sie sich den Code an und zählen Sie die Anzahl der Zweige, mit denen er arbeiten kann - diese Anzahl ist zyklomatische Komplexität.
Die zyklomatische Komplexität dieses Codes ist beispielsweise 1:

function main() {
 return 'Hello, World!';
}


Sie können nur einen Zweig der Ausführung dieses Codes verfolgen.
Fügen wir die bedingte Logik hinzu:

function main() {
 if (true) {
  return 'Hello, World!';
 } else {
  return 'Hello, unWorld!';
 }
}


Die zyklomatische Komplexität wurde auf 2 erhöht.

Perfekter Code ist leicht zu lesen und zu verstehen. Je höher die zyklomatische Komplexität, desto schwieriger wird es, den Code zu verstehen. Alle sind sich einig, dass eine hohe zyklomatische Komplexität schlecht ist, aber niemand an eine bestimmte Grenze stoßen kann. 5 ist gut und 100 ist zu viel. Und in der Mitte ist zu viel Unsicherheit.

Wenn die zyklomatische Komplexität einen vordefinierten Grenzwert erreicht, werden Sie von JSHint darüber informiert.

test.js: line 35, col 24, This function's cyclomatic complexity is too high. (17)


JSHint ist das einzige der drei Validierungsprogramme, das die zyklomatische Komplexität berücksichtigt. Hier können Sie auch ein Limit festlegen. Überschreiten Sie Ihre maximale Komplexität und JSHint wird Sie warnen. Ich mag es, das Limit auf 14 zu setzen, aber ich kann es in Projekten, in denen ich viel Parsing benötige, etwas höher einstellen.

Tatsächlich ist die Bedeutung von Komplexität wichtig, da sie Ihnen sagt, wann Sie den Code neu organisieren müssen. Wenn Sie zum ersten Mal eine lange Funktion schreiben, ist das wichtig. Wenn Sie jedoch ein halbes Jahr warten und dann zum Beheben von Fehlern zurückkehren, sind Sie froh, dass Sie sich die Zeit genommen haben, um die Lesbarkeit zu verbessern.

Die zyklomatische Komplexität wird normalerweise in eine Liste unterteilt. Ich habe beispielsweise einen Kalender erstellt und wollte für jedes Land den richtigen ersten Wochentag festlegen. Ich hatte eine Funktion, die so aussah:

function getFirstDay(country) {
 if (country === 'USA') {
  return 'Sunday';
 } else if (country === 'France') {
  return 'Monday';
 } else if…
}


Ich musste viele Länder abdecken, damit die zyklomatische Komplexität schnell über die 50er-Marke sprang. Obwohl der Code gut lesbar war, war die Anzahl der Zweige groß, sodass mein Code Analyzer nicht zufrieden war. Irgendwann habe ich die Funktion aufgeteilt und die Komplexität unter mein Maximum gesenkt. Für diesen speziellen Fall war es keine leichte Aufgabe, aber es ist ein niedriger Preis für saubereren Code im Allgemeinen.

Überprüfen Sie alles, was Sie mehr als einmal bearbeiten

Statische Analysegeräte finden Fehler, die Sie mit einfachen Tests nicht entdeckt hätten. Sie finden auch Fehler im Kompilierungsprozess und nicht während der Arbeit - dies sind die gleichen Mitternachtsfehler, die sich einschleichen, wenn ein Dutzend Menschen eine Sache aufgreifen. All diese subtilen Fehler zu finden, ohne den Code zu überprüfen, ist ein langer und schmerzhafter Prozess.

Ich habe diesen Artikel mit der Aussage begonnen, dass ich immer einen Codeanalysator verwende, aber ich mache dies nicht in einem Fall: wenn ich einmaligen Code schreibe. Ich verwende gerne schnelle Prototypen, um interaktive Ideen zu präsentieren und meinem Team zu zeigen, wie etwas funktionieren sollte. Solche Prototypen sind Einmalcodes. Ich muss hier keine Fehler beheben, da ich diesen Code in ein paar Wochen wegwerfen werde. Solch ein einmaliger Code existiert nur für kurze Demonstrationen, und es ist mir egal, ob darin subtile Fehler sind. Und alles, was mir wichtig ist, wird analysiert.

Das Beheben solcher Fehler zu Beginn eines Projekts ist relativ einfach. Wenn Sie sie in der Nacht vor der Veröffentlichung finden, können Sie verrückt werden. Codeanalysatoren haben mein Leben viele Male gerettet und werden daher Ihr Leben retten.


Jetzt auch beliebt: