Did you know that JavaScript has had labels since ES3?!?

twitter logo github logo ・1 min read

label - JavaScript MDN

Essentially it is something like goto but only for loops and labeled blocks.

js label

I'm curious to see what's the worst example you can think of using labels?

Or is there by any chance a very useful way to use them?

The possibilities are endless!

twitter logo DISCUSS (14)
markdown guide
 

break LABEL; is actually pretty common code

FOO:
for(...){
     for(...){
        if(...){
            break FOO;
        }
    }
}
 

I actually knew about that, but really, it's more of a curiosity than anything. Like in "see this weird trick in JavaScript!" "What?! Weiiiird..." Turns out that foo: 42 is a label followed by a number and not a key/value pair.

In JavaScript, especially in modern development, labels are basically useless.

Or is there by any chance a very useful way to use them?

The only decent use case is to break out of multiple loops. But then again, it's a very limited case where for some reason you have to use loops instead of a functional approach.

The possibilities are endless!

Fortunately they're not! πŸ˜‚

 

The only decent use case is to break out of multiple loops.

In PHP we have e.g. continue 2; (continue the parent loop), or break 3; (break the grandfather loop) for this purpose ;)

We have goto but there's basically no legitimate use for it. The docs page has a bit of an Easter egg agreeing with that :p php.net/manual/en/control-structur...

 

Uh. That's even worse. Now instead of a descriptive label, one has to count the nested loops to find out what the heck this statement affects.

I don't prefer it, just stating it's there ;-)

My favourite is Swift that has continue label or break label to refer to what to continue or break, but no accompanying goto which I think is an important safety decision.

developer.apple.com/library/conten...

gameLoop: while square != finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }
    switch square + diceRoll {
    case finalSquare:
        // diceRoll will move us to the final square, so the game is over
        break gameLoop
    case let newSquare where newSquare > finalSquare:
        // diceRoll will move us beyond the final square, so roll again
        continue gameLoop
    default:
        // this is a valid move, so find out its effect
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")
 

Labels are used together with goto statements (continue in JavaScript case), which encourage really unpredictable coding techniques and thus bad style that should be avoided. Having execution order controlling constructions like if statement and loops must be enough; once you define a loop there's no way to enter this loop skipping the initialization phase, the same is true for an if or else clause. Seeing a label in the source code cannot help you understand what's going on because you could possibly jump to this point from anywhere within the same file, under any circumstances.

On the other hand, the ability to stop the execution of not only an inner loop but also of any of outside ones using break <LABEL> seems much more reasonable at first glance. However, I would assume if you have a need to do that something might be really wrong with the algorithm you use - and it's better to revise it instead of using labeled breaks.

 

The worst potential issue I can come up with is that it's probably not clear what is going on in the code to the average JavaScript developer who is unaware of this language feature. Anything so uncommon is inherently dangerous.

 

Sure, you guys are talking about the worst way... but what about the BEST way?


JavaScript
dance:
for (let i = 0; i < 42; i++) {
    break dance;
}
 

When I first started programming as a kid (c. 2004) I loved BASIC, so I took every opportunity to look for BASIC compilers and interpreters on every platform I had. As a number of other commenters have implied, this is the only way of simulating BASIC's GOTO statements, so I had a relatively early exposure to this feature! Having said that, I have never used it in JavaScript (and now write much better code than in my childhood :')

 

This is actually a thing in Rust too.
Just that in Rust it is actually being used.

The best example is breaking out of nested loops:

#![allow(unreachable_code)]

fn main() {
    'outer: loop {
        println!("Entered the outer loop");

        'inner: loop {
            println!("Entered the inner loop");

            // This would break only the inner loop
            //break;

            // This breaks the outer loop
            break 'outer;
        }

        println!("This point will never be reached");
    }

    println!("Exited the outer loop");
}

(taken from rustbyexample.com)

Edit: Imagine for example a "mainloop". Usually it's a while running where running is a global mutable variable or something.
In Rust you don't need that condition, you can just break out of the outer loop.

Edit 2: This is especially useful since blocks in Rust can return a value. This way you can use a loop and break out of it with a value.
This is comparable to inlining a function that contains a loop and returns.

 

I didn't know this. I hope most people don't either. (Please don't use them)

Edit: An oldie, but a goodie that can have many parallels to this:
u.arizona.edu/~rubinson/copyright_...

 

I bet this post will spawn a bunch of new frameworks called "label.js" utilising this powerful feature...

 

I hope there is an initiative to remove them from the language specs.

 
Classic DEV Post from Mar 22

Opinion: Architect VS Engineer VS Developer

(Opinion) Architect VS Engineer VS Developer.

Dimitar Nestorov profile image
JavaScript, TypeScript, React, React Native, Node, and Electron