for..in (generally)
for..in
loops through the names of the properties of an object. People think it loops through the indexes of an array because the indexes of an array are names of properties on the array object, but that's a misconception.
So:
var obj = {foo: 1, bar: 2};
foo
and bar
are names of properties, and so:
var name;
for (name in obj) {
alert(name);
}
...will show "foo" and "bar" (in no particular order).
We'll come back to arrays in a moment. :-) Let's look at objects first.
Objects can have properties of their own, and properties they inherit from their prototype objects. The foo
and bar
properties above were direct properties of obj
, but:
function Thing() {
}
Thing.prototype.foo = 1;
var t = new Thing();
t.bar = 2;
Now our t
object has foo
and bar
, but foo
comes from the prototype, whereas bar
is its own property. In a for..in
, we can check which is which:
var name;
for (name in obj) {
alert(name + "(" + (obj.hasOwnProperty(name) ? "own" : "inherited") + ")");
}
...which will show "foo (inherited)" and "bar (own)" (in no particular order).
Objects can also have properties that are non-enumerable — they don't show up in for..in
loops. This is why if you do a for..in
on an array, the length
property doesn't show up, because length
is defined as a non-enumerable property. Nearly all of the standard properties on the standard objects are non-enumerable (including all of the ones that point to functions, like the toUpperCase
property on String
instances). (It used to be that only the ones in the spec could be non-enumerable, but ECMAScript 5th edition now provides ways for us to have our own non-enumerable properties.)
So, arrays. Arrays in Javascript are nothing like arrays in most other languages. (They are not contiguous blocks of memory, for one thing.) An array in Javascript is a standard object with a couple of special behaviors:
- The
length
property is always set to the next number above the property name with the highest numeric value that the array objects has. So if your highest array index is 2
, then length
will be 3.
- If you change
length
, any property whose name has a numeric value equal to or higher than the number you give length
will be deleted from the object.
That, and the functions they inherit from the Array.prototype
are pretty much all that's special about arrays in Javascript. All of their main functionality (storing and retrieving values) is just the standard Javascript object property behavior.
Your specific loop
For the above reasons, I wouldn't use for..in
for your loop. I'd either use jQuery#each
or a boring old-fashioned loop like you have. The latter would look like this:
var allSelected = $("select option:selected");
var totalSelected = allSelected.length; // <= No need to repeat the selector query
var index;
var anySelected = false;
for (index = 0; !anySelected && index < totalSelected; ++index) {
if (allSelected[index].value !== "0") {
anySelected = true;
}
}
if (anySelected) {
// do something with the selection
}
else [
// do something about their not having picked one
}
Don't use for..in
for Array iteration.
It's important to understand that Javascript Array's square bracket syntax ([]
) for accessing indicies is actually inherited from the Object
...
obj.prop === obj['prop'] // true
The for..in
structure does not work like a more traditional for..each/in
that would be found in other languages (php, python, etc...).
Javascript's for..in
is designed to iterate over the properties of an object. Producing the key of each property. Using this key combined with the Object
's bracket syntax, you can easily access the values you are after.
var obj = {
foo: "bar",
fizz: "buzz",
moo: "muck"
};
for ( var prop in obj ) {
console.log(prop); // foo / fizz / moo
console.log(obj[prop]); // bar / buzz / muck
}
And because the Array is simply an Object with sequential numeric property names (indexes) the for..in
works in a similar way, producing the numeric indicies just as it produces the property names above.
An important characteristic of the for..in
structure is that it continues to search for enumerable properties up the prototype chain. It will also iterate inherited enumerable properties. It is up to you to verify that the current property exists directly on the local object and not the prototype it is attached to with hasOwnProperty()
...
for ( var prop in obj ) {
if ( obj.hasOwnProperty(prop) ) {
// prop is actually obj's property (not inherited)
}
}
(More on Prototypal Inheritance)
The problem with using the for..in
structure on the Array type is that there is no garauntee as to what order the properties are produced... and generally speaking that is a farily important feature in processing an array.
Another problem is that it usually slower than a standard for
implementation.
Bottom Line
Using a for...in
to iterate arrays is like using the butt of a screw driver to drive a nail... why wouldn't you just use a hammer (for
)?
Best Answer
Use
var
, it reduces the scope of the variable otherwise the variable looks up to the nearest closure searching for avar
statement. If it cannot find avar
then it is global (if you are in a strict mode,using strict
, global variables throw an error). This can lead to problems like the following.If you write
var i
in the for loop the alert shows2
.JavaScript Scoping and Hoisting