I was exploring the Google Closure Compiler, and one thing I noticed was that it converts while(true) into for(;;).
Both do hang the browser, but why does the empty for loop not break out of itself immediately? The second part of it is empty, and therefore falsy. Isn't it true that when the second part is falsy, the for loop stops and execution continues with code which comes after the for loop?
Could someone perhaps give an explanation for this?
No, it is not true.
See: https://developer.mozilla.org/en/JavaScript/Reference/Statements/for
condition
An expression to be evaluated before each loop iteration. If this
expression evaluates to true,
statement is executed. This
conditional test is optional. If
omitted, the condition always
evaluates to true. If the expression
evaluates to false, execution skips to
the first expression following the for
construct.
I should perhaps give a link to ECMAScript reference, but I'm pretty sure it states more or less same thing.
From the ECMAScript language specification:
IterationStatement : for (ExpressionNoIn_opt ; Expression_opt ; Expression_opt) Statement
If the first Expression is present, then
Let testExprRef be the result of evaluating the first Expression.
If GetValue(testExprRef) is false, return (normal, V, empty).
Since the first expression (the second argument to for) is not present, this section is never run, so the for loop does not exit.
An empty middle part should be interpreted as true, so it's not falsy. It has the same semantics in C and other languages with that kind of loop (like C#, Java and so on). It would be a real trap to have changed it for JavaScript.
There is evaluation algorothm of for loop in Standard ECMA-262 script that says there are only two situations in which loop will end:
break statement
value of middle statement equal to false, but only if this statement is present, so it doesnt have to be necessary valuated as true (probably in mozilla js engine it is).
Related
Does an "if" statement with multiple "or" operators exit when the first condition returns true, or are all conditions evaluated?
i.e. does the order of your conditions matter?
Example scenario:
A shouldComponentUpdate() function with an if statement and the evaluated conditions vary in cost.
Does the order of the conditions (with the least expensive first) promise an improvement in performance or will the entire if statement get evaluated even if the first condition will return a true?
For example:
Assume an if statement in the form:
if ( (this.props.value != nextProps.value) || (deepDiffer(object1, object2) )
If (this.props.value != nextProps.value) returns true, will the code still evaluate the deepDiffer? Or will it immediately enter the if statement and execute the conditional code?
This is Javascript, so yes, it exits when the first condition is true.
According to MDN:
As logical expressions are evaluated left to right, they are tested
for possible "short-circuit" evaluation using the following rules:
false && anything is short-circuit evaluated to false.
true || anything is short-circuit evaluated to true.
The rules of logic guarantee that these evaluations are always correct. Note that the anything part of the above expressions is not evaluated, so any side
effects of doing so do not take effect.
In a condition, if there are multiple 'or', they are checked from left to right and if the first is true, it won't check the nexts.
Same behaviour in a 'and' chain, when the first false is encounter, the nexts won't be checked
This is basic Javascript
I was reading the answer to this question (about the "wat" video) and it said:
{}+[]
This is interpreted as an empty block of code, unary plus and empty array. First part does nothing, array is converted to a comma-separated string of it's elements (empty string for empty array), then to a number (empty string is converted to 0), hence 0.
I am currently learning JS from "The Definitive Guide" so I try to really understand things like that.
My question is, when does JS decide to interpret {} as an empty block of code, instead of an empty object?
Also, there are some inconsistencies between Node.js and Firebug which I would like to understand.
Firebug:
Node.js:
Let's look at the language grammar, shall we? Section 12, Statements:
Statement :
Block
VariableStatement
EmptyStatement
ExpressionStatement
...lots of other stuff...
That's a very fancy way of saying that a statement can be a block, a variable statement, an empty statement, an expression statement, or lots of other stuff. Notice that the first option there is a 'Block':
Block :
{ StatementList(opt) }
StatementList :
Statement
StatementList Statement
Which is again, a fancy way of saying that a block is a {, optionally followed by a bunch of statements, followed by a }.
And that's what you see in your example: Before the JavaScript parser thinks that what you have could be an object literal (which is defined somewhere under ExpressionStatement, the 4th thing a 'Statement' could be), it first thinks that you have a 'Block'.
Edit: If you want, you can see it live in a JavaScript engine's source code:
In V8, Chrome's JavaScript engine, we go into Parser::ParseStatement. The first thing it checks is whether we're on a {, and if it does, parses as block.
In SpiderMonkey, Firefox's JavaScript engine, we go from Parser::statement to again see the first check being against a { and parsing it as a block statement.
Regarding your second question, that's been covered to great detail on this question. To summarise in a sentence: Node.js treats your input as if it were an expression (thus it can't be a 'Block'), while Firebug/Chrome dev tools treat it like a 'Statement'.
When the first token in a new statement is {, then {} is interpreted as an empty block.
(Actually of course when { appears after the header clause of something like if or while, then {} is an empty block too, but that's not the interesting case.)
Thus in any other context, like say an argument to a function:
foo({});
the {} is interpreted as an empty object literal.
This situation is similar to the way in which the function keyword is treated differently when it's the first thing in a statement. The syntax has ambiguity, and the parser solves the problem with fixed rules.
I was reading the answer to this question (about the "wat" video) and it said:
{}+[]
This is interpreted as an empty block of code, unary plus and empty array. First part does nothing, array is converted to a comma-separated string of it's elements (empty string for empty array), then to a number (empty string is converted to 0), hence 0.
I am currently learning JS from "The Definitive Guide" so I try to really understand things like that.
My question is, when does JS decide to interpret {} as an empty block of code, instead of an empty object?
Also, there are some inconsistencies between Node.js and Firebug which I would like to understand.
Firebug:
Node.js:
Let's look at the language grammar, shall we? Section 12, Statements:
Statement :
Block
VariableStatement
EmptyStatement
ExpressionStatement
...lots of other stuff...
That's a very fancy way of saying that a statement can be a block, a variable statement, an empty statement, an expression statement, or lots of other stuff. Notice that the first option there is a 'Block':
Block :
{ StatementList(opt) }
StatementList :
Statement
StatementList Statement
Which is again, a fancy way of saying that a block is a {, optionally followed by a bunch of statements, followed by a }.
And that's what you see in your example: Before the JavaScript parser thinks that what you have could be an object literal (which is defined somewhere under ExpressionStatement, the 4th thing a 'Statement' could be), it first thinks that you have a 'Block'.
Edit: If you want, you can see it live in a JavaScript engine's source code:
In V8, Chrome's JavaScript engine, we go into Parser::ParseStatement. The first thing it checks is whether we're on a {, and if it does, parses as block.
In SpiderMonkey, Firefox's JavaScript engine, we go from Parser::statement to again see the first check being against a { and parsing it as a block statement.
Regarding your second question, that's been covered to great detail on this question. To summarise in a sentence: Node.js treats your input as if it were an expression (thus it can't be a 'Block'), while Firebug/Chrome dev tools treat it like a 'Statement'.
When the first token in a new statement is {, then {} is interpreted as an empty block.
(Actually of course when { appears after the header clause of something like if or while, then {} is an empty block too, but that's not the interesting case.)
Thus in any other context, like say an argument to a function:
foo({});
the {} is interpreted as an empty object literal.
This situation is similar to the way in which the function keyword is treated differently when it's the first thing in a statement. The syntax has ambiguity, and the parser solves the problem with fixed rules.
I ran into this piece of code:
<a ng-click= "item.statusId !== itemStatus.in || transfer()">
I guess we can generalize as:
<element ng-click = "someVar !== someValue || doStuff()">
I then found this article on short circuits and another more focused one once I knew what they are called. However, I still don't get it.
Does it basically work on the principle of an OR statement ending evaluation if the first statement evaluates to true? So if the first statement is true, end evaluation, if it's false, run the function in the second half of the OR statement? (This is the main question I am asking, everything else is extra).
I guess that part I don't get is whether the compiler interprets this code differently or it still evaluates to false and just runs the function. Not even sure how to phrase Q.
Does it basically work on the principle of an OR statement ending evaluation if the first statement evaluates to true? So if the first statement is true, end evaluation, if it's false, run the function in the second half of the OR statement?
It's effectively shorthand for an if statement, and you intuited correctly why it works. For more details on short-circuit evaluation in JavaScript, see this Stack Overflow question.
That code is equivalent to:
//Note the intentional and explicit use of `== false` to mean falsy (NOT `=== false` to indicate strict equality test for false)
if( (item.statusId !== itemStatus.in) == false ) {
transfer();
}
It is an interesting means of executing a function only when a condition is falsy.
There are many different examples of this around on StackOverflow, and is not specific to AngularJS.
While reading code from a JS Editor (Tern), I have come across various uses for the for-loop as seen in the snippets below:
code snippet 1 # lines 463-468:
for (;;) {
/* some code */
}
code snippet 2 # lines 97-100
for (var i = 0; ; ++i) {
/* some code */
}
On the same note, I also have come across a for-loop with an empty body e.g:
for (var p; p; p = someValue) /* empty body */ ;
I am trying to understand what happens in code execution flow.
My take is that for code in snippet 1, the for loop has no conditions, so it may continue endlessly? For code in snippet 2, i is continually incremented without a limit? For the third one, the loop continues till p is assigned something that evaluates to false?
These are the ideas I have in my mind yet I am not sure. Please assist.
In Short
First of all you are correct in all your assertions.
The first loop runs until it is exited from abruptly (with a break, return, throw etc..).
The second loop runs until it is exited from abruptly but also performs a variable assignment, and increments a value.
The third for loop runs like a normal for loop until the center condition is falsey. Its body is empty.
But Why does JavaScript do this?
Let's dig into why this happens.
If we take a closer look at the language specification we can see that the following happens in a for loop:
IterationStatement : for ( ExpressionNoIn(opt) ; Expression(opt) ; Expression(opt)) Statement
I will treat these statements and that definition for the rest of the answer.
Now let's go through the cases.
In case one of for(;;) the following happens:
ExpressionNoIn is not present, so nothing is called for that clause (As clause 1 states).
The second expression is not in, so we do not return calls (as clause 3 states).
The third expression is empty so no "incremenetion" is performed (as clause 3.f states).
So it would basically repeat endlessly just as you predicted (until broken from with a break or returned from, or thrown from and generally anything that causes abrupt completion). (As clauses e and d tell us).
In the second case for (var i = 0; ; ++i) the following happens:
ExpressionNoIn is present, so we evaluate it, and assign it with get value (as clause 1 states). We do not assign it.
Then we repeat endlessly since the second expression is not here. So we continue until abrubt execution happens or a break happens. More specifically this is defined here.
We increment i on every iteration as clause f states.
In the third case for (var p; p; p = someValue) /* empty body */ ; the following happens:
This evaluates as a for loop. Statement is empty indeed but the for loop does not really care. The only difference is that no value is returned from the for loop. Basically it's a full and legal for loop. ; is simply an empty statement. It is useful when you want to run a for loop with no content in the actual loop. You see this sometimes in feature detection. This is also useful when you want to find the minimum n such that... .
You are correct in that it runs until the value is falsey, or more accurately calling ToBoolean on it produces false. As clause 3.a.ii specifies.
As you can see, this is all in the spec and well defined :)
Why do coders do this?
In the first snippet the perform their flow control with a break clause. if (eol >= pos || eol < 0) break; (they check for the end of line, and this could be done in a more conventional for loop).
In the second snippet again they do flow control using break:
if (!definitions.hasOwnProperty(uniq)) { name = uniq; break; }
They again put it in a break statement inside the for loop.
The third snippet is out of context, but let's say we want to (trivial example) find the first number bigger than 10 (or the 10th div element, or occurance of a string - you get the idea). We could do :
for(var i=0;i<=10;i++);
And get the first number bigger than 10.
You are correct in your understanding.
The first snippet is an infinite loop; there is no termination condition, so the loop will (in itself) continue forever. This is almost certainly accompanied by a break statement somewhere within the body, which will exit the loop when it is run. (The other option is that a thrown exception exits the loop, although it is bad practice to use exceptions as control flow.) This pattern (or an equivalent while (true) {...} ) usually occurs when the exit condition is too complex to express within the loop statement.
The second snippet is similar to the first, in that without a termination condition it will run forever. This will also require a break statement (or exception) to terminate the loop. The only difference here is that a counter variable is also being incremented on each iteration.
The third snippet is a loop with no body, though the test and variable update happen on each iteration of the loop. As you expected, this continues until p evaluates to false. This for loop is exactly equivalent to the while loop version:
var p;
while (p) {
p = someValue;
}
which perhaps makes it clearer that the assignment happens repeatedly until !p.