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
}
Use var
, it reduces the scope of the variable otherwise the variable looks up to the nearest closure searching for a var
statement. If it cannot find a var
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.
function f (){
for (i=0; i<5; i++);
}
var i = 2;
f ();
alert (i); //i == 5. i should be 2
If you write var i
in the for loop the alert shows 2
.
JavaScript Scoping and Hoisting
Best Answer
You should always use
var
, if you want the value to be local.Using the keyword
object
for a variable, is not recommended, you might run into undefined behavior across browsers.Also you should generally avoid applying anything that is suppose to be local to the global scope.
This is bad:
This is correct:
If you need to access this value in the global scope, you are probably doing it wrong. Also having this in the global scope is useless, as it will only be the last value, that will exist in the varName.