Vielleicht fragt ihr ich euch jetzt: Was?! Das war auch meine erste Reaktion, als ich von Labeled Statements (Anweisungen mit Bezeichnung) gehört habe. Was also sind sie und wann können sie verwendet werden?
Sind es goto Anweisungen?
Viele Programmiersprachen haben goto
Anweisungen. Einige Programmiersprachen haben sie sogar erst in späteren Versionen eingeführt, so wie PHP in Version 5.3. Und so würden sie in PHP aussehen:
$array = [
'one' => [ 1, 2, 3 ],
'two' => [ 4, 5, 6 ],
];
foreach ( $array as $key => $numbers ) {
foreach ( $numbers as $number ) {
if ( $number === 4 ) {
goto fourFound;
}
}
}
echo "There is no 4 in the array";
goto end;
fourFound:
printf( "There is a 4 in array '%s'", $key );
end:
In diesem Beispiel haben wir zwei foreach-Schleifen verwenden. Der Code versucht, in einem zweidimensionalen Array eine 4 zu finden. Sobald eine 4 gefunden wird, können wir die Schleifen beenden und das Ergebnis ausgeben. Um die Schleife(n) zu verlassen, verwendet dieser Code eine goto
Anweisung. Dazu springt es in Zeile 17 zum Label fourFound
, wo wir dann das Ergebnis ausgeben. Es gibt auch eine zweite goto
Anweisung in Zeile 15, die zum end
Label springen würde. In jedem Fall würde nur eine echo
/printf
Funktion aufgerufen werden.
Mit etwas Erfahrung in der Entwicklung von gutem Code, erkennt man hier mehrere Möglichkeiten, um diesen Code zu verbessern. Ich hoffe aber, dass er trotzdem demonstrieren kann, wie ein goto
in PHP (und vielen anderen Sprachen) funktioniert. Aber was sind nun Labeled Statements in JavaScript? Sie ähneln den hier gezeigten Labels in PHP, aber es sind keine goto
Anweisung und diese Labels können nur in Kombination mit dem break
oder continue
Keyword verwendet werden.
Wie könnt continue und break in eurem Code verwenden?
Wenn ihr eine Schleife habt, dann könnt ihr aus der Schleife ausbrechen, indem ihr die break
Anweisung wie folgt verwendet:
const numbers = [1, 2, 3, 4, 5, 6];
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] === 4) {
console.log(`Found 4 at index ${i}`);
break;
}
}
Dieser Code würde das numbers
Array durchlaufen, aber sobald die 4 gefunden wurde, würde der Code aus dem Array „ausbrechen“ und sich die anderen Werte nicht weiter ansehen.
Die continue
Anweisung kann verwendet werden, um die aktuelle Iteration zu beenden und mit der nächsten zu beginnen. Wie in diesem modifizierten Beispiel:
for ( let i = 0; i < numbers.length; i++ ) {
if ( numbers[i] % 2 !== 0 ) {
continue;
}
if ( numbers[i] === 4 ) {
console.log( `Found 4 at index ${i}` );
break;
}
}
In Zeile 2 wird geprüft, ob die aktuelle Zahl ungerade ist. Wenn das der Fall ist, kann es sich nicht um die gesuchte Zahl 4 handeln. Wir verwenden dann die continue
Anweisung, um mit der nächsten Iteration zu beginnen, womit die Bedingung in Zeile 5 nicht ausgeführt wird.
Wie überspringt man eine „innere Schleife“?
Nehmen wir wieder das erste Codebeispiel aus PHP und verwenden hier die break
Anweisung anstelle einer goto
Anweisung:
$array = [
'one' => [ 1, 2, 3 ],
'two' => [ 4, 5, 6 ],
];
foreach ( $array as $key => $numbers ) {
foreach ( $numbers as $number ) {
if ( $number === 4 ) {
break 2;
}
}
}
if ( $number === 4 ) {
printf( "There is a 4 in array '%s'", $key );
} else {
echo "There is no 4 in the array";
}
In PHP können wir break 2
verwenden, um nicht nur die „innere Schleife“, sondern auch die „äußere Schleife“ zu verlassen. Die Zahl nach break
gibt also an, aus wie vielen „Kontrollstrukturen“ wir ausbrechen wollen. Etwas Ähnliches ist mit continue 2
möglich, wobei das Programm mit der nächsten Iteration der „äußeren Schleife“ fortfahren würde.
In JavaScript ist dies jedoch nicht möglich. Ihr könnt nach einer break
oder continue
Anweisung keine Zahl verwenden. Und genau hier kommen die Labeled Statements ins Spiel.
Ausbrechen aus einer inneren Schleife in JavaScript
Wenn wir versuchen, denselben Code wie oben in JavaScript zu erstellen, können wir eine beschriftete Anweisung wie in diesem Code verwenden:
var array = {
one: [1, 2, 3],
two: [4, 5, 6],
};
outerLoop:
for ( var key in array ) {
var numbers = array[key];
for ( var i = 0; i < numbers.length; i++ ) {
if ( numbers[i] === 4 ) {
break outerLoop;
}
}
}
if ( numbers[i] === 4 ) {
console.log( `there is a 4 in array ${key}'` );
} else {
console.log( "There is no 4 in the array" );
}
Das Label muss nicht in einer eigenen Zeile stehen, es kann auch in einer Zeile mit der for
Schleife stehen. Zur besseren Lesbarkeit habe ich es einfach so formatiert.
Wenn ihr jeder Schleife ein Label voranstellt, können ihr jeweils eine andere break
Anweisung verwenden, um zu einer beliebigen Schleife zu springen. Das Gleiche gilt für continue
.
Wofür sollte ich das verwenden?
Sollten ihr also Labeled Statements verwenden? Mein Rat wäre ähnlich wie der, den der xkcd-Comic über goto
gibt: Verwendet sie nicht!
Wenn ihr Code schreibt, der von etwas wie break 2
, continue 2
oder dem JavaScript-Äquivalent mit einem Labeled Statement profitieren würde, wäre das für mich ein klares Zeichen, dass dieses Stück Code überarbeitet werden sollte.
Anstatt ein goto
zu verwenden, um aus einer Schleife herauszuspringen, sollten ihr diese Schleife in eine Funktion verschieben und return
verwenden. Und für verschachtelte Schleifen könnt ihr auch verschachtelte Funktionen in Schleifen verwenden.
Im vorherigen Code gibt es viele Dinge zu optimieren, nicht nur die verschachtelten Schleifen. Mit einigen modernen JavaScript-Funktionen könnte er so aussehen:
const array = {
one: [1, 2, 3],
two: [4, 5, 6],
};
function findTheFour(obj) {
for (const property in obj) {
if (obj[property].includes(4)) {
return property;
}
}
return null;
}
const found = findTheFour(array);
if ( found ) {
console.log( `there is a 4 in array ${found}'` );
} else {
console.log( "There is no 4 in the array" );
}
Ist das nicht viel einfacher zu lesen? Wenn wir die Funktion includes()
für Arrays verwenden, können wir sogar die „innere Schleife“ vermeiden. Und wir brauchen keine Labeled Statements.
Fazit
Ihr werdet euch jetzt vielleicht fragen, warum ich euch dieses Feature von JavaScript gezeigt habe, und dann von der Verwendung abrate. Nun, es gibt Code, der sie verwendet, den ihr dann vielleicht nicht versteht, wenn ihr noch nie Labeled Statements oder goto
in anderen Programmiersprachen gesehen habt. Und ich habe euch noch nicht mal gezeigt, was man damit alles machen kann. Lest Sie also ruhig die Dokumentation dazu, und vielleicht finden ihr ja einen Anwendungsfall, bei dem es für euer Codebasis wirklich von Nutzen sein kann, was immer das auch sein mag.