my first question here:
I was learning about loops from developer.mozzila.org and this was an example for 'break;'
The user provides a name and this code searches through the array contacts and returns the number.
const contacts = ['Chris:2232322', 'Sarah:3453456', 'Bill:7654322', 'Mary:9998769', 'Dianne:9384975'];
const para = document.querySelector('p');
const input = document.querySelector('input');
const btn = document.querySelector('button');
btn.addEventListener('click', function() {
let searchName = input.value.toLowerCase();
input.value = '';
input.focus();
for (let i = 0; i < contacts.length; i++) {
let splitContact = contacts[i].split(':');
if (splitContact[0].toLowerCase() === searchName) {
para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.';
break;
} else {
para.textContent = 'Contact not found.';
}
}
});
I'm failing to understand how this code is not returning 'Contact not found.' on every iteration. Instead, according to MDN, it only does so if the name is not found in the array. Won't the code under 'else' execute every time the 'if' condition is not met?
Thanks and apologies if I'm missed some StackOverflow etiquette.
I'm failing to understand how this code is not returning 'Contact not found.'
This code is not returning anything, it's performing an operation. It may seem like a nitpick, but it's an important distinction. Because returning will end the execution of the function, but performing an operation will not.
Won't the code under 'else' execute every time the 'if' condition is not met?
Indeed it will! Which is an astute observation on your part. But the question at that point is not necessarily whether the else block will be executed at all, but rather...
What happens when the else block is executed?
What does the if block do differently?
What will be the state of the system after the loop finishes?
In this case the else block can execute as many times as the loop iterates, and nothing will change. It repeats the same non-destructive operation over and over, changing nothing. But if the if block ever executes, the break causes the loop to terminate. So either the if block will never execute, or it will be the last operation to execute.
Thus, the state after the loop will either be that the else block executed multiple times or that the if block was the last thing to execute and the last thing to change the state.
Consider as a simple thought experiment example, what happens if you set a variable to 0 a hundred times? It's 0. What happens if you set it to 0 a hundred times and then set it to 1? It's 1. Repeating the former operation many times makes no difference on the resulting state. One may be able to argue a performance impact, but if that's negligible (which it is here) then it may not be worth addressing.
I'm failing to understand how this code is not returning 'Contact not found.' on every iteration. Instead, according to MDN, it only does so if the name is not found in the array. Won't the code under 'else' execute every time the 'if' condition is not met?
It's not returning anything, it's setting a DOM element's property to something. And it is indeed setting it to Contact not found. for every iteration until (if) it finds what it's searching for, in which case it will set it to the found string and then break out of the loop.
It's inefficient, but the end result is most likely going to be the one you'd expect.
Yes you are right,
it will set para.textContent each time splitContact[0].toLowerCase() !== searchName, but it won't end, so it doesn't break the loop or doesn't return, so it continue to the end
Related
In his article on let and const Jason Orendorff states the following:
Crunchy performance details: In most cases, you can tell whether the
declaration has run or not just by looking at the code, so the
JavaScript engine does not actually need to perform an extra check
every time the variable is accessed to make sure it’s been
initialized. However, inside a closure, it sometimes isn’t clear. In
those cases the JavaScript engine will do a run-time check. That means
let can be a touch slower than var.
I decided to try and find an example where this held true and was stumped.
For example, let us look at the following torture scenario:
function doSomethingDumb(q) {
function crash() { ++x; }
q.fn = crash;
crash();
let x;
return crash;
}
Even though the closure is returned at the end of the function, it is guaranteed that the return statement will never execute, even though x is assigned to a member of q (and thus may escape into the wild) x will never be initialized and thus crash will always crash.
In what case would it be impossible to tell whether the variable had been initialized?
Just put that into a condition that is only sometimes fulfilled:
function example() {
if (Math.random() < 0.33) tryIt();
const x = 5;
if (Math.random() < 0.5) tryIt();
function tryIt() {
console.log(x);
}
}
In this example I've chosen a random, but it could as well depend on the function's input parameters. In general, it is not statically decidable whether the statement that accesses the variable will be executed before the initialisation - that's the halting problem. You can write a sophisticated analyser that can determine this for many cases, but there's always a trade off between sophistication and overhead of the analyser.
There is no such thing as slow or fast handle, i.e.: named value, be it a var a const or a let. There's no such thing as "unable to determine" if they are initialized either.
Moreover let/s don't get initialized - they simply get assigned. And since they are made to act similar to 'undeclared variables' they will be assigned their value at runtime and exactly at their point declaration.
Therefore, if a stop error happens occur just one line above the let declaration. It will remain fully undeclared. An you will know it just by looking at the code.
The continue statement in javascript doesn't really make sense to me, or am I over thinking this?
For example, let's say I am for inning inside an object:
for (i in JM) {
if (JM[i].event == 'StartLocation') {
continue;
}
}
If that if statement is true, it's going to technically hop over that iteration. Why do we use the word continue then? Wouldn't it make more sense to use the word break? But, break does the total opposite, it stops the loop, right? (Or maybe a statement called hop) would make sense. Never really thought of this until a couple minutes ago :P
Yes, break takes you out of the loop and places you at the line after the loop. continue takes you directly back to the start of the next iteration of the loop, skipping over any lines left in the loop.
for(i in JM)
{ // continue takes you directly here
if(JM[i].event=='StartLocation'){
continue;
}
// some other code
} // break takes you directly here
If you're only asking about the word choice, then there probably isn't a great answer to this question. Using continue does cause loop iteration to continue, just on the next iteration. Any keyword could have been chosen. The first person to specify a language with this behavior just chose the word "continue."
The continue keyword is similar to break, in that it influences the progress
of a loop. When continue is encountered in a loop body, control jumps
out of the body and continues with the loop’s next iteration.
Understand it like this:
for(i in JM){
if(JM[i].event=='StartLocation'){
continue;
}
/*This code won't executed if the if statement is true and instead will move to next iteration*/
var testCode = 3;// Dummy code
}
break will break the for loop(come out of for loop) but continue will skip the current iteration and will move to next iteration.
You will find the relevant docs Here.
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.
I am completing a book called "DOM Scripting - Web Design with JavaScript and the Document Object Model" written by Jeremy Keith.
Here is the 'do...while' example given:
var count = 1;
do {
console.log(count);
count++;
} while (count < 11);
In the book he has stated that if we look at our do...while loop example we can be formulate it in full like this:
initialize;
while (condition) {
statements;
increment;
}
Surely this is in fact a mistake and this is actually the formulation of a while loop and not a do...while loop.
I have also checked the Errata to see if this was an error in the book but there is no mention of it.
Am I correct in saying this is the formulation of a while loop and not a do...while loop? Is there some authoritative ECMAScript documentation I can consult?
In the book that you mentioned above , do-while has been described like this :
As with the if statement, it is possible that the statements contained within the curly
braces of a while loop may never be executed. If the condition evaluates as false on the
first loop, then the code won’t be executed even once.
There are times when you will want the code contained within a loop to be executed at
least once. In this case, it’s best to use a do loop. This is the syntax for a do loop:
do {
statements;
} while (condition);
This is very similar to the syntax for a regular while loop, but with a subtle difference. Even
if the condition evaluates as false on the very first loop, the statements contained within
the curly braces will still be executed once.
So it becomes clear after reading this section that the author never says that do-while and while are the same. What he says is that, whatever you are doing using while, you can do the same using do-while. However, in a while, if condition evaluates to false during the first iteration itself, it will not even enter the loop. But in do-while, since iteration in the syntax is specified later, so it will enter the loop at least once. That's pretty much what he means.
Can anyone tell me why in the following code a do/while lop is used rather than a simple if statement:
function prev(elem){
do {
elem = elem.previousSibling;
} while(elem && elem.nodeType != 1);
return elem;
}
Why not:
function prev(elem){
if(elem && elem.nodeType != 1) {
elem = elem.previousSibling;
return elem;
}
Is there an advantage to using do/while? Thanks!
do-while will run once and continue running while the statement is true, while the if-statement will only run once.
In this instance it may be equivalent (depending on how the code and data is set up), but typically that is how do-whiles are used.
If you want something to keep repeating until a certain condition is met, use the do,for, or while statement. If you only want to check something once, use the if statement.
If you are using do while loop, then your statements will execute atleast once. Then a condition is checked and if the condition is not satisfied then the statement are not executed any more. But if you use the other option then first condition is checked and if the condition is satisfied then the statements are executed only once. Otherwise they are not executed even a single time.
A While or Do While statement is a continuous loop until a condition is met.
An If, Then, Else/Else If is a simple evaluative statement rather than a loop.
Here do-while will run atleast once, and will execute until while condition is met.
But in the if-statement, it'll check the condition first, and will execute once only and will return the response.