I came across this snippet reading MDN's tutorial "A re-introduction to JavaScript (JS tutorial)":
function countChars(elm) {
if (elm.nodeType == 3) { // TEXT_NODE
return elm.nodeValue.length;
}
var count = 0;
for (var i = 0, child; child = elm.childNodes[i]; i++) {
count += countChars(child);
}
return count;
}
What I don't understand is the for loop statement. Specifically, the condition statement child = elm.childNodes[i]. I always learned that the condition in a loop should be a logical one. For me, that's an assignment.
What am I losing?
4 Answers 4
When the i in child = elm.childNodes[i] is bigger than the length of the array, the deklaration gets evalutated to undefined. And in js undefined is equal to false Boolean(undefined) -> false.
Because of that, this is a boolean equation.
That kind of equation is danger because if the array contains an element that is equal to false (null, 0, false), the loop will stop without iterating all elements.
6 Comments
false, it's falsy, which is different ! As childNodes returns elements, it would never return false or 0Boolean(undefined) === false -> true Thats feels like equal for mevar a=[false]; for(var i =0; child = a[i]; i++){ console.log("this will never be seen")} in this case it returns false with the first element.undefined === false is not true, so it's not strictly equal unless you convert it to a boolean, which means it's not equal, it's falsy, not false0 will of course void the loop, but childNodes doesn't return zeros, it returns DOM nodesThe condition of for loop here is the value of the assignment oprator = (which is in other words the value elm.childNodes[i]).
var a,
assignmentOperatorValue = ( a = 5 );
// ^^^^^^^^^ this yields 5 which is then assigned to assignmentOperatorValue, you can even pass that value to a function like: func(a = 5);
console.log(assignmentOperatorValue);
If elm.childNodes[i] is an element (truthy value) then the condition is true.
If elm.childNodes[i] is undefined (falsy value) then the condition is false.
Comments
for loops are built by 3 parts:
- initialization
- condition
- final-expression
In your case - the condition part is child = elm.childNodes[i];.
When accessing element of list that is our-of-range - the value you will get is undefined and the condition will result in breaking the loop.
Comments
You're right to recognize that this is an assignment, and I personally would avoid writing a loop like this because it can be confusing to other developers. However, it actually works because every assignment expression returns the value that was assigned. For example, after the following statement, both a and b will have a value of 1:
var a, b;
a = b = 1;
If elm.childNodes is an array, then child = elm.childNodes[i] will both assign child's value and return the value of elm.childNodes[i]. If elm.childNodes[i] is truthy, then the loop will continue. Otherwise it will break.
So this loop could break when it reaches an index higher than the last value in the array, or if the value at an index is 0, false, null or any other falsy value in the JavaScript language. It's likely that the programmer is just assuming that all values in the array will have to be valid objects that won't evaluate to false.
null, or in this caseundefined, and asnullandundefinedare both falsy, the assigment, or rather the assigned value it returns, can also be used as a condition.