We wrześniu zastanawiałem się nad tym, jak obsługiwać asynchroniczność w ES3. Wspominałem tam o mechanizmach pozwalających na przekazywanie sterowania. Otóż myślałem nad tym potem trochę i uświadomiłem sobie, że istnieje jeszcze co najmniej jeden taki mechanizm: pętle. I nieco ich nadużywając można zrobić… goto.

Etykiety

Ale zanim przejdziemy do pętli, pora poznać inny mechanizm, który będzie nam potrzebny: etykiety. Niemal każda instrukcja w JS może zostać w takową zaopatrzona. Jak wygląda etykieta? Dość prosto:

hublabubla: console.log( 'whatever' );

hublabubla to właśnie nasza etykieta! Całość mocno przypomina definiowanie właściwości obiektu – tylko obiektu brakuje.

Na chwilę obecną etykiety w JS po prostu . Nie da się ich zastosować niemal do niczego, a sam język przewiduje, że da się ich użyć wyłącznie ze słowami kluczowymi continue i break, czyli w pętlach. To pozwala na przykład przerywać zewnętrzną pętlę z poziomu tej zagnieżdżonej:

outer: while( true ) {
	while( true ) {
		break outer;
	}
}

console.log( 'I wyskoczyliśmy!' );

Myślę, że Co Bardziej Rozgarnięci Czytelnicy dostrzegają już ten ukryty potencjał!

goto w JS

Jeśli jesteśmy dostatecznymi masochistami, nic nie stoi na przeszkodzie, by podzielić nasz kod na wiele zagnieżdżonych i oetykietowanych pętli, między którymi będziemy przeskakiwać przy pomocy continue <etykieta>. Tego typu program mógłby wyglądać następująco:

main: while( true ) { // 1
	let name;

	askForName: while( true ) { // 2
		name = prompt( 'Podaj imię' );

		checkName: while( !name ) { // 3
			continue askForName; // 4
		}

		displayName: while( name ) { // 5
			console.log( name );

			break main; // 6
		}
	}
}

Sporo kodu jak dla tak prostego programu. Jego zadaniem jest wyświetlenie imienia podanego przez użytkownika. Na początku tworzymy pętlę main (1), w której zamykamy cały program. Następnie tworzymy pętlę askForName (2), której zadaniem jest pobranie nazwy od użytkownika. Kolejna pętla (3) sprawdza, czy imię zostało podane. Jeśli nie, przekazuje sterowanie z powrotem do pętli askForName (4) – to jest właśnie nasze goto. Ta pętla jest tak naprawdę odpowiednikiem instrukcji warunkowej if – no bo po co nam ona, skoro wszystko da się ograć pętlami! Jeśli warunek pętli checkName nie został spełniony (a więc użytkownik podał imię), wchodzimy do ostatniej pętli (5), która wyświetla imię w konsoli i przerywa główną pętlę (6).

Brawo, udało nam się przenieść jedną z największych abominacji programowania do JS! Niestety, nie byliśmy pierwsi, bo pomysł był znany od dawna. I mam nadzieję, że pozostanie tym, czym od zawsze był: żartem i ciekawostką. Nie chcę nosić do końca życia brzemienia osoby, która skalała JS goto