20

On a lot of browsers I've tested, JavaScript blocks actually return a value. You can test it out in any console:

for(var i = 0; i < 10; i++) {
    var sqrt = Math.sqrt(i);
    if(Math.floor(sqrt) === sqrt) {
        i;
    }
}

The "return" value is the last square number, that is, 9! But since it isn't an expression I suppose, you can't do this:

for(var i = 0; i < 10; i++) {
    ...
} + 5

That doesn't work. It gives + 5, or 5, of course, because it's a separate statement. Putting the loop in parentheses obviously fails, and if a block is in parentheses (e.g. ({f(); r}) - doesn't work) it's treated as an object and throws a syntax error.

One way to take advantage of the return value, as such, is to use eval:

eval('for(var i = 0; i < 10; i++) {var sqrt = Math.sqrt(i);if(Math.floor(sqrt) === sqrt) {i;}}') + 5; // 14

But I'm obviously not going to want to use that if eval is the only solution. Is there a way to use a block's resultant value without using eval that I'm missing? I really like this feature :)

18
  • 4
    Blocks are statements, not expressions. Therefore, you can't use them as operands (you can't use operators on them)... Commented Dec 23, 2011 at 16:23
  • 1
    You should treat eval's return value as the anomaly, not the restriction that JS "normally" (read: ignoring outside eval) imposes. Blocks are not expressions. Commented Dec 23, 2011 at 16:26
  • 1
    @ŠimeVidas: Because it's interesting is all. If there's a good way to get this to work in any JavaScript engine, it would be interesting to see all the syntactic sugar you can add :) Even if it's not for production purposes. Commented Dec 23, 2011 at 16:29
  • 1
    Are you sure that what you are observing is blocks returning values instead of consoles being designed to print the last thing that is evaluated? (which means that the console is really printing the final i; instead of what you think the for loop returns, assuming that in reality the for loop doesn't return anything). Commented Dec 23, 2011 at 16:33
  • 4
    @minitech eval() returns the completion value of the JavaScript program that has been passed in as source text. This is an interesting point. Other than this, I am not aware of any other method to receive the completion value of a program/statement... Commented Dec 23, 2011 at 16:39

2 Answers 2

18

In JavaScript, statements return values of the Completion type (which is not a language type, but a specification type).

The Completion type is used to explain the behaviour of statements (break, continue, return and throw) that perform nonlocal transfers of control. Values of the Completion type are triples of the form (type, value, target), where type is one of normal, break, continue, return, or throw, value is any ECMAScript language value or empty, and target is any ECMAScript identifier or empty.

Source: http://es5.github.com/x8.html#x8.9

So, eval() evaluates the program that has been passed in as source text. That program (like any JavaScript program) returns a Completion value. The second item in this Completion value (the "value" item) is returned by the eval() invocation.

So, with eval you are able to retrieve the completion value of an JavaScript program. I am not aware of any other method to accomplish this...

Sign up to request clarification or add additional context in comments.

4 Comments

I'd bet that this completion type stuff is there just to specify some original eval implementation.
@missingno I can assure you that the completion type is an essential part of the language. Completion values are used by the interpreter to determine the next step in execution (i.e. transfer control to the caller function, jump to the beginning of the iteration statement, etc.).
Sorry, for the confusion. I can't think of any case other then eval that cares about the completion value. (The second value in that triple, and the one that matters for this particular question)
@hugomg throw and return needs those values, or else how are you expecting to "return" a value? It may be that eval is the only thing that cares about the value in a NORMAL typed completion.
9

There is a proposal for ES7 to introduce a do expression which allows any block to be turned into an expression. A do expression evaluates a block and returns its completion value.

Using this syntax, which you can try out today with Babel using the syntax-do-expression and transform-do-expression plugins, your example would look like this:

function lastSquareNumber(val) {
    return do { for(var i = 0; i < val; i++) {
        var sqrt = Math.sqrt(i);
        if(Math.floor(sqrt) === sqrt) {
            i;
        }
    }}
}

console.log(lastSquareNumber(10));

2 Comments

Cool! I somehow doubt that it’ll make it, but it’s good too see all the same.
This looks very neat, I hope this gets implemented in ES7 tho we'll have to wait for that for another while I guess :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.