I found these lines of code in a library made to listen to touch events :
for ( var i = elements.length; i; i-- ) {
iterator( elements[ i - 1 ], elements );
}
It surprised me for a second. I understand the code this way : i is an integer positive or null and the conditional statement is if i positive.
Do I understand right ? Does i return false when i==-1 ? Or did i miss something (like it's possible to write a for loop without a conditional statement) ?
The conditional is essentially if( i) proceedToNextIteration();
As numbers go, only zero is falsy and would fail the check. -1 would be true in the above condition.
For this reason, I'd rewrite that code as:
for( var i = elements.length-1; i >= 0; i--) {
iterator( elements[i], elements);
}
It's much more explicit about its final condition.
This is the structure of the for statement in Javascript:
for ([initialization]; [condition]; [final-expression])
statement
The statement you provided
for ( var i = elements.length; i; i-- )
adheres to this syntax. This is same as
for(var i = 10; i!=0; i--)
Meaning loop from 10 (elements.length) to 1. Similar to looping from 1 to 10.
In Javascript, the condition i != 0 can be replaced with just i.
Meaning:
if(i != 0)
and
if (i)
are the same. That is what is done in the condition part.
Looping over elements of a list or array from max to 0 is helpful when removing items from it.
Related
I am a beginner in code world. I have troubles understanding recursion in JavaScript especially when it needs two or more looping. Like I want to print rectangle using recursion. I don't know completely how to make a base case, condition when it still executed. For examples, these codes below I use to print rectangle or holey rectangle.
function box(num) {
for (let i = 0; i < num; i++) {
let str = ''
for (let j = 0; j < num; j++) {
str += '*'
}
console.log(str)
}
}
box(5)
function holeBox (num) {
for(let i = 0; i < num; i++){
let str = ''
for(let j = 0; j < num; j++){
if(i == 0 || i == num -1 || j == 0 || j == num - 1) {
str += '*'
} else {
str += ' '
}
}
console.log(str)
}
}
holeBox (5)
Please help me to understand recursion, an explanation would be great. My goals are not only to solve those codes but also to understand how recursion works. I've searched there's no good source to learn recursion, or I just too dumb to understand. Thanks in advance
To understand how recursion works, just think of how you can split up what you want to accomplish into smaller tasks, and how the function can complete one of those tasks, and then call itself to do the next- and so on until it is finished. I personally don't think printing boxes is the best way to learn recursion, so imagine you wanted to search an array for a specific value; ignore JavaScript's indexOf()/find() functions or similar for now.
To do this using loops, its easy, just iterate over the array, and check every value:
//Returns the index of the first occurrence of a value in an array, or -1 if nothing is found
function search(needle, haystack) {
for (let i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) return i;
}
return -1;
}
Doing this using recursion is easy as well:
function recursiveSearch(needle, haystack, i) {
if (i > (haystack.length - 1)) return -1; //check if we are at the end of the array
if (haystack[i] == needle) return i; //check if we've found what we're looking for
//if we haven't found the value yet and we're not at the end of the array, call this function to look at the next element
return recursiveSearch(needle, haystack, i + 1);
}
These functions do the same thing, just differently. In the recursive function, the two if statements are the base cases. The function:
Tests if the current element is out of bounds of the array (meaning we've already searched every element), and if so, returns -1
Tests if the current element is what we're looking for, and if so, returns the index
If neither of the statements above apply, we call this function recursively to check the next element
Repeat this until one of the base cases kicks in.
Note that recursive functions are usually called from other helper functions so that you don't have to pass the initial parameters to call the function. For example, the recursiveSearch() function above would be private, and it would be called by another function like this:
function search(needle, haystack) {
return recursiveSearch(needle, haystack, 0);
}
so that we don't have to include the third parameter when we call it, thus decreasing confusion.
Yes, even your box code can be turn into recursion but I don't think it will help you understand the concept of recursion.
If you really have to:
function getBox(arr, size) {
let length = arr.length;
if (length == size)
return arr; // recursion stop rule - if the size reached
for (let i = 0; i < length; i++)
arr[i].push("*"); // fill new size for all row
arr.push(new Array(length + 1).fill("*")); // add new row
return getBox(arr, size); // recursive call with arr bigger in 1 row
}
However, I believe #Gumbo answer explain the concept better then this...
i searched around for a couple of questions related to the use of the for loop and the setInterval function in JavaScript but i couldn´t find a concrete answer on why this snippet doesn´t work. Could someone explain please what´s happening under the hood and why this code doesn´t print anything at all?
for (let i = 0; i++; i < 10) {
window.setInterval(function () {
console.log('Test');
} , 100)
}
Your for loop is not correct. The condition needs to be the second statement in the for loop.
Following code should work.
for (let i = 0; i < 10 ; i++; ) {
window.setInterval(function () {
console.log('Test');
} , 100)
}
Expected Syntax for loop. You can read more here
for ([initialization]; [condition]; [final-expression])
statement
EDIT 1:
Though all answers (including mine) mentioned that condition needs to be second statement in the for loop which is correct. There is one more additional important behavior.
The for loop for (let i = 0; i++; i < 10) is actually correct in terms of grammar and even the javascript runtime executes this code.
But, as in your case, if the condition is evaluating to falsy value then it would exit the loop.
Breaking your for loop for (let i = 0; i++; i < 10) into each seperate construct
Initialization: let i = 0; This statement initializes the value of variable i to 0.
Condition: i++; Javascript evaluates the statement to check if the statement is true or not. In case of i++ the runtime firstly checks for the current value of i which is 0 . Since 0 is considered a falsy value the condition evaluates to false and hence the statement is not executed. Also, i++ statement is a post increment which basically increments i and then result the original value of i.
So, if you would have written loop like below, using the intiliaztion of i=1, then it would have worked, though it would be running infinitely untill the browser/Server crashes as the condition i++ would always evaluate to true. I hope that makes sense.
for (let i = 1; i++; i < 10) {
// Statements would run
}
Or
for (let i = 0; ++i; i < 10) { **// Pre increment**
// Statements would run
}
Or
for (let i = 0; i=i+1; i < 10) { **// increment i by assigment
// Statements would run
}
Douglas Crockford in his book Good Parts mention about the usage of ++ & -- and how it can confuse readers.
your for loop syntax is wrong, should be
for (let i = 0; i < 10; i++)
your setInterval code will run every 100 milliseconds for each iteration of the loop (so 10 times every 100 milliseconds)
Nothing to do with setInterval, you simply malformed your for loop:
This:
for (let i = 0; i++; i < 10)
Should be this:
for (let i = 0; i < 10; i++)
First declare the initial state of the loop, then the terminating state of the loop, then the incremental change of the loop.
Observe.
Recently I was going through some JavaScript code and at multiple places they are using a while loop to iterate over arrays. The way they do it is as
var i = dataArray.length;
while ( i-- ) {
// iterating over the array.
}
We know that the post-decrement operator here would first supply the value to while call and then will reduce it by one. So in this case for the first iteration if the array length is 10, the while call checks for i to be 10 and we get the value of i inside the loop to be 9. This continues till i reaches a value of 0 and then we exit out of loop. Precisely speaking we are iterating the array in a reverse manner.
This is fine. Where it really confuses me is when I write a pre-decrement operator, the while loop runs forever resulting in a stack overflow.
var i = dataArray.length;
while ( --i ){
// This loop would run forever.
}
Why is this happening? Won't doing --i will also result into i hitting the 0 value at some point of time and breaking the loop?
This is only the case if dataArray is empty. In that casen i = dataArray.length becomes zero. Then when you enter the while loop, i is pre-decremented to -1. Since all non-zero numbers evaluate to true, the loop keeps on going forever.
However, if the array has any elements, this will not happend and the loop will terminate. This code will illustrate the effect without craching anything:
function loop(x) {
var i = x.length;
while ( --i ) {
console.log(i);
if(i == -5) break; //Break after a while so we avoid an endless loop.
}
}
loop([]);
loop([1,1,1]);
The output of the first call is -1, -2, -3, -4, -5, and the output of the second call is 2, 1.
JSFiddle.
Ideal way of writing While loop.
while(condition){
// Your code
// iterator update (i++/i--)
}
Why you loop stops? JavaScript considers 0 as false and stops when reaches 0.
Also can't tell why predecrement runs forever. This might be because i never reaches 0;
Loop simulation
var data = [];
function createArray(){
for (var i=0; i<10; i++){
data.push(i);
}
}
function preDecrementLoop(){
var i = data.length;
while(--i){
console.log(i);
}
}
function postDecrementLoop(){
var i = data.length;
while(i--){
console.log(i);
}
}
(function(){
createArray();
console.log("pre decrement");
preDecrementLoop();
console.log("post decrement");
postDecrementLoop();
})()
Note: --i will skip loop for 0 since 0 is considered as false, while (0) == while (false).
Is there any way I can prevent javascript from dropping an error if I try to go into a non existing array index?
Example: array[-1] would return error and eventually break all my code. How can I let it just return 'undefined' and let my script go on? I can implement an if statement before checking the array (so that if the index is minor than zero or major than the array size it would skip it) but this would be very tedious!
this is my code:
if (grid[j-1][i])
n++;
if (grid[j+1][i])
n++;
if (grid[j][i+1])
n++;
if (grid[j][i-1])
n++;
if (grid[j-1][i-1])
n++;
if (grid[j+1][i+1])
n++;
if (grid[j-1][i+1])
n++;
if (grid[j+1][i-1])
n++;
It is inside of two loops which both sees J and I starting from zero. I don't want to change them and neither writing another if statement (as you can see, there are already too much of them!). Is there any solution?
Thanks!
If you know the measures of your grid, you can put "sentinel cells" around it.
If you add a -1st index to an array x, it does not count to x.length. Putting an additional last element into the list would increment x.length.
I daresay using sentinel cells combined with the arithmetic counting algorithms mentioned by d_inevitable would be the fastest solution, since it would not involve branches. You even can omit the !! because true will evaluate to 1 and false to 0 in an equalization.
Update:
Do not use index -1. Its an awful lot slower that normal array indexes. See http://jsperf.com/index-1.
You could use ||, which muffles errors, e.g.:
(grid[j-1] || [])[i] || false
(I haven't tested this, but it should work)
Edit: updated based on am not i am's suggestion
A less tedious way while still using ifs would be checking the first index if it's defined:
if (typeof grid[j-1] != "undefined" && grid[j-1][i])
You could create a function to do the checks:
function getArrayValue(arr,key) {
if( key < 0 || key >= arr.length) return null;
return arr[key];
}
But really you should be avoiding out-of-bounds keys anyway.
I would do this:
for(m = Math.max(j-1,0) ; m <= Math.min(j+1,grid.length-1) ; m++)
for (p = Math.max(i-1,0) ; p <= Math.min(i+1, grid[m].length-1) ; p++)
n += !(m == j && p == i) && !!grid[m][p];
How about this for your solution?
for (dj = -1; dj <= 1; ++dj) {
for (di = -1; di <= 1; ++di) {
if ((dj || di) && grid[j+dj] && grid[j+dj][i+di]) {
n++;
}
}
}
If you refactor all those ifs into a single loop like the above, then having to do the extra conditional is not so bad.
array ref.length = 7 (0 - 6), and I want to try to match ref[0]['x'] to ref[1]['x'] I am doing this:
for(var i=0;i<ref.length;i++){
if( ref[i]['x'] != ref[i+1]['x'] && ref[i+1]['x'].length > 0 )
//do something
}
The for loop is iterating all the way to array number 6 then element 6+1 is blank so I get an error on the if statement line saying ref[i+1] is undefined....
is there a better way to do this?
Better:
for (var i=ref.length-2;i>=0;i--)
Javascript will evaluate the condition on each iteration, so it's generally preferable go backwards instead. With this construct "ref.length" is only evaluated once. Another alternative I like which will perform the same:
var i=ref.length-1;
while (i--) {
}
(Normally you'd be i=ref.length-1 in the first example, and i=ref.length in the second, but you're trying to stay one less than the array length).
for (var i=0; i<ref.length-1; i++) { // Note the "-1".
This way when you use the index i+1 you're still in bounds.
for (var i = 0; i < ref.length - 1; i++)
What about:
for(var i=0;i<ref.length-1;i++){
If you just use ref.length-1 won't that solve your problem? I might not fully understand what you're asking.
Here's a simple solution.
Just count the counter again.
if( ref[i]['x'] != ref[++i]['x'] && ref[++i]['x'].length > 0 )