how this for loop determines when to break the loop - javascript

I have encountered a different type of for loop which i don't see or use commonly.I tried to figure it out but get even more confused in the process.It doesn't have its third argument or even a check method to break the loop.Here it iterates over an array and prints its value.Actually it encounters 'undefined' value for a certain index but i am not telling it to break when it will encounter undefined.please help me to break the puzzle here...
(function () {
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
for (var i = 0, value; value = a[i++];) {
document.write(value + '</br>');
}
})();

In javascript, when you access array elements beyond the length of the array, you don't get a range check error, the returned value is undefined which corresponds to false when treated as boolean - thus the loop termination when the end of the array is reached.
If any of the array elements is undefined or any other value that becomes false as boolean, the loop will terminate on that element.
The assignment operator in javascript returns a value of the left side, so expression value = a[i++] is used to return the value of a[i] and increment i - in that order. If this value converts to false as boolean, the loop is terminated.

All arguments to for loops are optional.
The first statement in a for loop is just a variable declaration, as such you are allowed to define multiple variables. The author could've instead written:
var a=[1,2,3,4,5,6,7,8,9];
var value;
for(var i = 0; value = a[i++];)
but went for brevity instead.
The third statement (increment/decrement) is optional, the author (again going for absolute brevity) decided to use postfix increment (i++ will return i THEN increment it, whereas ++i will increment THEN return the incremented value).
They also could've written this:
(function () {
var a = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var value;
var i = 0;
for ( ; value = a[i++]; ) {
document.write(value + '</br>');
}
})();
Finally, a[a.length+1] which would be the final condition evaluated returns undefined, which is a falsy value and will cause the loop to terminate.

A couple of things to note:
undefined is a "falsy" (not-true) value
A loop terminates when its condition becomes non-true
Assigning a[i] (or a[i++]) to value returns value
So, when i == 9, a[i++] == undefined, so value == undefined, so the loop terminates.

for (var i = 0, value; value = a[i++];) {
the second part of for is evaluated as a condition for each iteration.
automatic type conversion happens here so that the value of a[i++] is evaluated. if a[i++] is true the loop continues, if not it stops.

For loop repeats until condition after the first ; is true. In your case eventually after the last element in the array a[i++] will become falsy (ToBoolean(undefined)). Once it happens loop stops.
Take a look at specification for For Statement:
Repeat
a. If the first Expression is present, then
i. Let testExprRef be the result of evaluating the first Expression.
ii. If ToBoolean(GetValue(testExprRef)) is false, return (normal, V, empty).

Related

Ternary operator condition

The following code uses the reduce method. It outputs the number of times an element appears in the array. If element appears once then it only outputs 1, otherwise if it is a repeated item then it it is added..
let a = ["a", "b", "c", "a", "b"]
const t = a.reduce((aa, ll) => {
const count = aa[ll];
count
?
aa[ll] = count + 1 :
aa[ll] = 1
return aa
}, {})
console.log(JSON.stringify(t))
// output
// { "a":2, "b":2, "c":1 }
Question is regarding the condition in the ternary operation, specifically the count variable. How is the count variable able to resolve true or false.
The concept is called "Truthy" and "Falsy" respectively. Ie anything that is different from false, 0, -0, 0n, NaN, null, undefined and "" (empty string) can be evaluated to true in Javascript
So your assign var counter = aa[ll] to be the value of the key ll in object aa. That's either a number or undefined. If it's a number !== 0 it's a truthy, if it's 0 or undefined it's falsy. Thus it can be used in a ternary operatator. Depending on the value of counter either the value of the first or the second assignment will be returned (but ignored). The return value of an assignment is always the value of the right hand side ...
While you can use also assignments in the expressions of a ternary operator, I personally wouldn't use it that way but write this assignment as follows
const t = a.reduce((aa, ll) => {
aa[ll] = (aa[ll] || 0) + 1;
return aa
}, {})
(aa[ll] || 0) will return the value of aa[ll] if it's a truthy or 0 otherwise. Thus, in your case, the result of this expression will always be a number >= 0. Then you increase the result by 1 (for the currenct occurence of ll) and assign it back to aa[ll]. This is much shorter than your original code and IMHO much more readable
Heres the answer I found.
"A javascript object consists of key-value pairs where keys are unique. If you try to add a duplicate key with a different value, then the older value for that key is overwritten by the new value."
basically the count variable was checking to see if the new property already exists.

Clarification on For/Over Loop with Conditionals

Reading through O'Reilly's JS Definitive Guide and came across this block of code:
let freq = {};
for (let item of "alabama") {
if (freq[item]) {
freq[item]++;
} else {
freq[item] = 1;
}
}
Just want to go over some of the the syntax and implications:
Assigning an empty object to "freq" variable
Running the for/of loop over the given string
If statement checks if freq[item] returns true .. I get that part but what will trigger that truthy value?
And thus what how would a falsy value be triggered to produce a value of 1?
Thank in advance!
First, keep in mind that when iterating over a string with for..of, the item declared for each loop (which you've named item) is each character of the string.
Since the object starts out empty, freq[item] will initially be undefined. For example, on the first iteration, {}['a'] is undefined, which is falsey, so the else is entered:
freq['a'] = 1;
On subsequent iterations, when the character a is found, the a property will exist on the object, so the if is entered, incrementing that property value:
freq['a']++;
The first time you find a letter not in the object it will return undefined
1) a
freq['a'] will be undefined
therefore the code will set a 1 to it
freq['a'] = 1
2) l will go through the same steps as #1
3) a
freq['a'] will be 1
so it's truthy therfore we add 1 to it
freg['a'] ++; which will make it 2
Then you can follow same pattern to figure out the rest
in javascript the following are false
"",false,0,undefined,null..
in you case freq is an empty object
freq ={}
in first iteration of loop
item = 'a'
freq[item] will be undefined
if freq[item] will be false
so in else freq[item] = 1 ie. freq={a:1}
same way for second iteration freq={a:1,l:1}
for third iteration
item = 'a'
freq[item] will be 1
if freq[item] will be true and increments freq={a:2,l:1}

JavaScript - Factorialization 'For Loop' Understanding?

I am in the midst of completing some JavaScript algorithmic challenges and I had to factorialize a number as part of one of them. After searching through stack and other places I entered a correct code block:
function factorialize(num) {
if(num === 0) {
return 1;
}
if(num < 0 ) {
return undefined;
}
for(var i = num; --i; ) {
num *= i;
}
return num;
}
factorialize(5);
It it returns a correct result. What I am struggling to understand however is why the for loop doesn't have a second statement, and why it can run for ever? I have an inkling it's because as soon as i value is 0, any subsequent negative number that is generated will be multiplied by 0 and so only the integer numbers will form the result. But why does the function return a valid number, if the loop is still running to -infinity and hasn't been told to stop when reaching a certain value?
the second part of your for loop is the 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.
Once --i reaches 0, it evaluates to false (falsey) and the for "exits"
adding a console.log(i) to your for loop will help demonstrate that
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for
All elements in a for-loop's expression are optional.
The second part of the for-loop is used to express the for-loop's condition. The condition is evaluated on every iteration, and when it evaluates to false, the loop is exited.
In this case, that second part that expresses the condition is --i. This means that on every iteration, i will be decremented by 1, until it finally reaches zero (0). Since 0 is considered to be a falsey value in Javascript, the loop exits.
for (a; b; c)
is a direct equivalent to
a;
while (b) {
c;
}
You're mistaken here because you seem to think that c is what determines the end of the loop, but b actually is. You can omit the third loop statement if you don't need it (as well as the first one).
Here, your loop is equivalent to:
var i = num;
while (--i) {
num *= i;
}
while (--i) does two things:
Decrement i (before anything else)
Check that i != 0 (this is the actual loop condition).
If it was i--, note that the operations would be done in the opposite order.
If you find the code hard to read, you can also write it this way for the same results:
for (var i = num - 1; i != 0; i--) {
num *= i;
}
Normally you would have :
for(var i = 0; i < num; i++)
the second statement is a boolean continuation expression.
So when you have
for(var i = num; i--;)
The second is still a boolean continuation expression and when i get to 0 it evaluated to false.

Difference between two variable one is assigned a value undefined and second one is only declared a var not initialized

What is different between two variable one is assigned a value undefined and second one is only declared a var not initiased ?
var a = undefined;
var b;
a === b; // returns true
What is different between two variable a and b?
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
ar.filter(function(item, index, arr){
return item == undefined;
}); // [null, undefined]
I know Array's filter function runs for only initialized index.
How javascript internally check that ar[1] is assigend undefined so run filter for this and ar[2] is unassigned undefined so dont run for this ?
There are three separate issues going on here:
A regular variable that has just been declared, but not assigned a value will report undefined when you read that variable. That is essentially its default value.
You have to be very careful when comparing null with == because you will find that null == undefined is true because of auto-type conversion. So, if you want to filter on only undefined elements, you have to use item === undefined in the filter.
.filter() only iterates elements in the array that have actually been assigned a value. Unlike plain variables, there is a difference between an array element that has assigned a value and one that has never been assigned a value and .filter() knows to skip the ones that have never been assigned a value (the ones that are essentially "sparse").
Here's some more detail on these three issues:
A variable that has been declared, but not explicitly initialized, has a value of undefined. That is its default value.
This, this code is as expected:
var a = undefined;
var b;
a === b; // returns true
Then, in your second code block, if you want to truly test for whether something is undefined, then you need to use ===, not == to avoid any type conversion.
var ar = new Array(4); // ar = 0[undefined × 4]
ar[0] = null; // ar = [null, undefined × 3]
ar[1] = undefined; // ar = [null, undefined, undefined × 2]
var result = ar.filter(function(item, index, arr){
return item === undefined;
});
for (var i = 0; i < result.length; i++) {
document.write(i, ": ", result[i], "<br>");
}
Note: .filter() will skip elements of the array that have not been initialized to have any value, thus they will never even be considered in the .filter() operation. If you try to read their values, you will get undefined, but .filter() knows the difference between a "sparse" array value that has never been assigned anything. It has to do with whether the array key exists or not, not what the value is and thus it is different for array items than it is for plain variables.
From the MDN doc for .filter():
The range of elements processed by filter() is set before the first
invocation of callback. Elements which are appended to the array after
the call to filter() begins will not be visited by callback. If
existing elements of the array are changed, or deleted, their value as
passed to callback will be the value at the time filter() visits them;
elements that are deleted are not visited.
Here's a demonstration of how the array keys do not actually exist until someting is assigned to the array element. This is the information that .filter() uses to know what to iterate and what to skip:
var ar = new Array(4);
ar[1] = "foo";
ar[2] = undefined;
for (var index in ar) {
document.write(index, ": ", ar[index], "<br>"); // 1 foo, 2 undefined
}
Note that indexes 0 and 3 are not iterated with the for loop because those keys do not exist in the array. The array is "sparse". Only some elements actually exist.

Push to an Array using a for loop

im a JS newbie. Trying to figure out this problem below. I am stuck on the "if" statement and not sure exactly what to put in. Also im not sure if my "push" is setup right
// Define a function named `compact` that accepts an array and returns
// another array with all the falsey values removed from it. For example,
// if this array was passed in:
// [1, 4, 0, '', undefined, false, true, null, {mj: 'mj'}, 'Hello']
// the function would return this, as a result:
// [1, 4, true, {mj: 'mj'}, 'Hello']
var compact = function (array) {
var truthyValues = [];
for (var i = 0; i < array.length; i += 1) {
if () {
truthyValues.push[i];
}
}
return truthyValues;
};
You're close. Here's what the if should be:
if (array[i]) {
truthyValues.push(array[i]);
}
Since you want to check for truthiness of each array element, just put array[i] in the if block. That gets the value of the array at i, and will evaluate as true if that value is truthy.
Then push not i - the index into array - but array[i], so that the actual value is in truthyValues.
Just put the value you want to check is truthy in the if statement, since the if statement checks for truthiness.
if(array[i]){
truthyValues.push(array[i]);
}
I think you can just use:
if (array[i]) { truthyValues.push(array[i]); }
Values like null will trigger false.
if (typeof array[i] !== "undefined" && array[i] !== null) {// push to array // }
most of these other answers will not work for falsy and existy values. You'll need to define what you intend to be existy and write a helper function for that. you could use the one I provided as a start and then roll your own.

Categories