views:

539

answers:

4

In Java you can use a for() loop to go through objects in an array like so:

String[] myStringArray = {"Hello","World"};
for(String s : myStringArray)
{
    //Do something
}

can you do the same in JavaScript?

A: 

In javascript the only similar syntax is:

for(var i in myStringArray){
  var s = myStringArray[i];
}
zipcodeman
Awesome, Thanks!
Mark Szymanski
You should avoid this method though, look at this question for example: http://stackoverflow.com/questions/1885317/strange-behavior-in-javascript-enhanced-for-in-loop
serg
@Mark: Just be aware, that's *not* the purpose of the `for-in` statement... it might look similar the `foreach` statement of other languages like Java or C#, etc... but in JavaScript `for-in` is not recommended for iterating array-like objects. See the details on my answer.
CMS
+21  A: 

Use a sequential for loop:

var myStringArray = ["Hello","World"];
for (var i = 0; i < myStringArray.length; i++) {
    alert(myStringArray[i]);
    //Do something
}

@zipcodeman suggests the use of the for...in statement, but for iterating arrays for-in should be avoided, that statement is meant to enumerate object properties.

It shouldn't be used for array-like objects because:

  • The order of iteration is not guaranteed, the array indexes may not visited in the numeric order.
  • Inherited properties are also enumerated.

The second point is can give you a lot of problems, for example, if you extend the Array.prototype object to include a method there, that property will be also enumerated.

For example:

Array.prototype.foo = "foo!";
var array = ['a', 'b', 'c'];

for (var i in array) {
  alert(array[i]);
}

The above code will alert, "a", "b", "c" and "foo!".

That be particularly a problem if you use some library that relies heavily on native prototypes augmention (such as MooTools for example).

The for-in statement as I said before it's there to enumerate object properties, for example:

var obj = {
  "a": 1,
  "b": 2,
  "c": 3
};

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) { 
  // or if (Object.prototype.hasOwnProperty.call(obj,prop)) for safety...
    alert("prop: " + prop + " value: " + obj[prop])
  }
}

In the above example the hasOwnProperty method allows you to enumerate only own properties, that's it, only the properties that the object physically has, no inherited properties.

I would recommend you to read the following article:

CMS
Why the down-vote? `for...in` should be *avoided* for Array-like objects!
CMS
Why should it be avoided?
Mark Szymanski
Yeah, the down vote was mine, I un-did it though.
Mark Szymanski
This is the reason ( by CMS him self ) http://stackoverflow.com/questions/1885317/strange-behavior-in-javascript-enhanced-for-in-loop/1885365#1885365
OscarRyz
+1 for adding explanation why not to use `for( in ) `
OscarRyz
+6  A: 

You can use map (also known as apply in other languages like python, and probably haskell too)

[1,2,3,4].map( function(item) {
     alert(item);
})

The general syntax is:

array.map(func)

func should take one parameter.

The return value of array.map is another array, so you can use it like this:

var x = [1,2,3,4].map( function(item) { return item * 10; } );

And now x is [10,20,30,40]

EDIT:

I must clarify: this concept is from the functional paradigm.

You don't have to write the function inline; one might do so as a first sketch, but you could then extract it into its own function.

var item_processor = function(item) {
      // do something complicated to an item 
}

new_list = my_list.map(item_processor);

which would be sort-of equivalent to:

 for(item in my_list) { item_porcessor(item); }

except you don't get the new_list.

hasen j
Woah, and that's not a `for()` loop like I was looking for.
Mark Szymanski
No, but it can be more powerful. check this out: http://www.joelonsoftware.com/items/2006/08/01.html
hasen j
+1 [..........]
OscarRyz
That particular example is probably better implemented using `Array.forEach`. `map` is for generating a new array.
harto
@harto, can you post an answer with that? I'm interested
OscarRyz
@harto, me too; never heard of it
hasen j
@hasen, the `Array.prototype.map` method is part of the ECMAScript 5th Edition Standard, is not yet available on all implementations (e.g. IE lacks of it), also for *iterating* over an array I think the [`Array.prototype.forEach`](https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Objects/Array/ForEach) method is more *semantically* correct... also please don't suggest the for-in statement, see my answer for more details :)
CMS
aagh .. remind me again why I hate IE?
hasen j
It's available in some libraries, eg jQuery... but is not really meant for iterating over things. At least semantically, it doesn't imply that things actually happen in any given order. Thus the name: you are `map`ping one set of values to another, not processing them iteratively.
intuited
If you check out the link CMS provided, there's an implementation you can use in browsers that don't natively support it.
harto
@intuited, I'd say the same applies to the foreach loop in java/c#/python; theoretically they can be applied in a random order (i.e. in parallel across multiple processors or even multiple machines). I'd also say that the body of the foreach loop is nothing but the body of the function that's being passed to `map`.
hasen j
@hasen j: that's not been my understanding, mostly based on the fact that the foreach loop is derived from the for loop rather than from functional programming concepts. Also the fact that it's called a "loop" :)
intuited
+3  A: 

Opera, Safari, Firefox and Chrome now all share a set of enhanced Array methods for optimizing many common loops.

You may not need all of them, but they can be very useful, or would be if every browser supported them.

The mozilla labs published the algorithms they and webkit both use, so that you can add them yourself.

filter returns an array of items that satisfy some condition or test.

every returns true if every array member passes the test.

some returns true if any pass the test.

forEach runs a function on each array member and doesn't return anything.

map is like forEach, but it returns an array of the results of the operation for each element.

These methods all take a function for their first argument, and have an optional second argument, which is an object whose scope you want to impose on the array members as they loop through the function.

Ignore it until you need it.

indexOf and lastIndexOf find the appropriate position of the first or last element that matches its argument exactly.

(function(){
    var p, ap= Array.prototype, p2={
        filter: function(fun, scope){
            var L= this.length, A= [], i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        val= this[i];
                        if(fun.call(scope, val, i, this)){
                            A[A.length]= val;
                        }
                    }
                    ++i;
                }
            }
            return A;
        },
        every: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && !fun.call(scope, this[i], i, this)) return false;
                    ++i;
                }
                return true;
            }
            return null;
        },
        forEach: function(fun, scope){
            var L= this.length, i= 0;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
            }
            return this;
        },
        indexOf: function(what, i){
            i= i || 0;
            var L= this.length;
            while(i< L){
                if(this[i]=== what) return i;
                ++i;
            }
            return -1;
        },
        lastIndexOf: function(what, i){
            var L= this.length;
            i= i || L-1;
            if(isNaN(i) || i>= L) i= L-1;
            else if(i< 0) i += L;
            while(i> -1){
                if(this[i]=== what) return i;
                --i;
            }
            return -1;
        },
        map: function(fun, scope){
            var L= this.length, A= Array(this.length), i= 0, val;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in this){
                        A[i]= fun.call(scope, this[i], i, this);
                    }
                    ++i;
                }
                return A;
            }
        },
        some: function(fun, scope){
            var i= 0, L= this.length;
            if(typeof fun== 'function'){
                while(i<L){
                    if(i in this && fun.call(scope, this[i], i, this)) return true;
                    ++i;
                }
                return false;
            }
        }
    }
    for(p in p2){
        if(!ap[p]) ap[p]= p2[p];
    }
    return true;
})();
kennebec