"foreach" in Javascript

Asked

Viewed 66,760 times

29

By way of example, in PHP we have the function foreach() (English) which allows us to execute a certain code for each element found in a matrix:

<?php
$arr = array(1, 2, 3, 4, 5, 6);

foreach ($arr as $value) {
  echo "acção para o valor " . $value;
}

// Saída:
// acção para o valor 1
// ...
?>

Using the same function, we can go through the matrix and get the key and its value for each element found:

<?php
$arr = array(
  "primeiro" => "John",
  "ultimo"   => "Doe"
);

foreach ($arr as $key => $value) {
  echo $key . ' nome: ' . $value . "<br>";
}

// Saída:
// primeiro nome: John
// ultimo nome: Doe
?>

Question

How can I perform this type of operation with a Javascript array ?

6 answers

29


First of all, PHP arrays are different from Javascript arrays

An example of traditional matrix would be:

var matriz = [1,2,3,4];

Whereas in PHP is an associative array, in Javascript is an object:

var obj = {
    primeiro: 'John',
    ultimo: 'Doe'
};

As @utluiz said, in Javascript exists the for. in, that serves to iterate over the keys of an object. Since arrays are also objects, it is also possible to iterate on them, but this is not recommended due to some features of for..in:

  1. The for..in iterates over all the object’s enumerable keys.
  2. The for..in also iterates over all property keys (enumerable) inherited from the prototype object.
  3. The Javascript specification does not require a specific order for the keys traversed by for..in. Different browsers can use different orders and it is possible that the vector keys will not be accessed in ascending order.

These features can cause problems, especially if you use libraries or polyfills modifying Array.prototype.

So don’t use for..in to iterate over an array; use a for common

var matriz = [1,2,3,4];
for(var i=0; i<matriz.length; i++) {
    console.log(i, matriz[i]); // i é o índice, matriz[i] é o valor
}

If you want something a little closer to the PHP version:

var matriz = [1,2,3,4];
for(var chave=0, valor; valor=matriz[chave], chave<matriz.length; chave++) {
    console.log(chave, valor); // chave é o índice, valor é o valor
}

There are also other alternatives, in browsers with Ecmascript 5 support (which does not include IE8). For example, the forEach mentioned by Luiz Vieira:

var matriz = [1,2,3,4];
matriz.forEach(function(valor, chave){
    console.log(chave, valor);
});

If the purpose of the iteration is to create a new matrix with transformations of the original values, you can use the map:

var matriz = [1,2,3,4];
// Nova matriz onde cada valor é o dobro
var dobros = matriz.map(function(valor){
    return valor * 2;
});
console.log(dobros); // [2,4,6,8];

If the goal is to create a new matrix with only some of the original values, you can use the filter:

var matriz = [1,2,3,4];
// Nova matriz só com valores pares
var pares = matriz.filter(function(valor){
    return valor % 2 == 0;
});
console.log(pares); // [2,4];

In this same line, it is worth taking a look at the methods reduce, every and some.

To iterate over objects, then use the for..in

var obj = {
    primeiro: 'John',
    ultimo: 'Doe'
};
for(var tipoNome in obj) {
    console.log(tipoNome, obj[tipoNome]);
}

But beware: this type of iteration may include inherited properties. For example:

function Cachorro(nome) {
    this.nome = nome;
}
Cachorro.prototype.latir = function() {
    console.log('au au!');    
};
var godofredo = new Cachorro('Godofredo');
for(var prop in godofredo) {
    console.log(prop); // loga 'latir' e 'nome'
}

To avoid the problem, you can make a check with hasOwnProperty:

for(var prop in godofredo) {
    if(godofredo.hasOwnProperty(prop)) {
        console.log(prop); // loga somente 'nome'
    }
}    
  • Congratulations on the answer! Very didactic and enlightening. (y)

7

Via jQuery, for a simple approach, you can use the jQuery.each() method that allows you to iterate over objects/arrays by separating them by index/value

Example:

$.each([ 'a', 'b', 'c' ], function( index, value ) {
    alert( index + ": " + value );
});

Reference: http://api.jquery.com/jquery.each/

7

Similar alternative: for..in

In Javascript there is a version of for that has some similarities with the foreach PHP. It is the closest type of construction, but it exists to iterate on object properties and not necessarily vector indices. Also, it is not possible to get the key and value automatically.

The syntax is:

for (<índice> in <vetor/objeto>)

Example:

var array = [1, 2, 3, 4];
for (index in array) {
    var value = array[index];
    console.log("array[" + index + "] = " + value);
}

Functional example in jsfiddle.

Iterating on object properties

As I mentioned, this kind of loop is not directed exactly to arrays, being mainly useful to iterate on the properties of any object:

Example:

var object = { nome: 'Luiz', idade: 29};
for (property in object) {
    var value = object[property];
    console.log("object[" + property + "] = " + value);
}

Functional example in jsfiddle.

A common application is to simulate a map or data dictionary. Another example is a sparse vector (which does not contain all indices sequentially from 0 to n.

Attention to possible problems

As mentioned in other responses and comments, the loop for...in may result in unwanted side effects.

For example, if a library defines one or more functions in the prototype of the object. These functions will be included in the for..in and it would be necessary to use the function hasOwnProperty to ignore these "inherited functions".

Moreover, it is not guaranteed that numerical indexes will be traversed in some order.

Tip: avoid touching the prototype

From my point of view, tampering with prototype of common objects should be avoided at all costs, as well as libraries that make such use.

For example, imagine that we will use an object as a map, dynamically assigning and retrieving attributes from it. As I walk through the keys to this map, at all times use the function hasOwnProperty.

The question is: should we really have to worry that someone injected some "strange" element into our objects? I believe that.

In practice...

Although the for..in always be accused of causing problems, in my experience I have never had difficulties in using it so much in arrays how much in objects normal, without the hasOwnProperty. Probably this is due to the fact that I never allow "strange" code injecting "magic" functions without my knowledge.

Moreover, although the order of the elements is not guaranteed by the specification, I have also never witnessed in any browser indexes being traversed out of order, at least in arrays for real.

See the example below:

var array = new Array();

array.push("A");
array.push("B");
array.push("C");

delete array[1]
array[1] = 2;

for (i in array) {
    console.log(i)
}

Even deleting a middle index of the array and then redefining it, the result will be 0, 1 and 2, in this order. See the jsfiddle. If anyone discovers a browser that behaves differently, please let me know.

On the other hand, if not use a array for real the result is different. See the example below:

var array = { }

array[0] = "A";
array[2] = "B";
array[1] = "C";

for (i in array) {
    console.log(i)
}

See the jsfiddle.

Surprisingly, the result in Chrome is 0, 1 and 2. However, in Firefox and IE is 0, 2 and 1. Anyway, unless you use an object as a sparse vector, that is, adding larger elements before the smaller ones, there would be no problem in using the for..in.

Anyway, the same care for using the for..in in arrays serves for any object, so recommendations like "don’t use it" simply don’t make sense. Even if the prototype is changed as long as I always use the hasOwnProperty() and do not mind the order of the elements, there is no problem in using this type of loop.

Final considerations

Generally speaking, it’s really best to avoid the for..in and opt for the for traditional. Reasons:

  • You may need a library to change the prototype. It is common to hear reports from people who add a certain Javascript library and it "breaks" its implementation.
  • It also prevents other developers from misusing prototype and break the general system code.
  • Allows objects to simulate a array, defining the property length and numeric attributes. This is very useful for generic routines that receive vectors. See the example below:

    var array = {
        0: "Primeiro",
        1: "Segundo",
        2: "Terceiro",
        length: 3
    };
    
    for (var i = 0; i < array.length; i++) {
        console.log('array[' + i + '] = ' + array[i]);
    }
    

See the jsfiddle.

  • 1

    Do not use for-in to iterate vectors. There is no guarantee that indices will be accessed in ascending order (which is what most programmers expect)

  • 1

    @I find that kind of statement very superficial. I like to give people options and not simply restrict the use of a resource just because can cause some side effect. I reworked the answer with a deeper analysis of the question. I’m a little out of time, but feel free if you have any comments or criticisms that sooner or later I’ll stop by for another review. Hug.

4

In addition to all existing answers, there is the for... of Ecmascript 6 (i.e., new :/) which traverses object values including a special property Symbol.iterator (this property is a symbol... and remembering that symbols are not enumerable! ). Instances of Array, Map, Set, String and TypedArray, and the object arguments generated by functions are already traversable, provided they have the special property Symbol.iterator.

Note: There is only one drawback to using for... of. He won’t let you know the current value index.

P.S.: the above mentioned classes/interfaces store this property Symbol.iterator in the prototype itself. This property should return a function (if you see in the console, [][Symbol.iterator], will come across a named function 'values'), and that same function should return an object. [][Symbol.iterator]() returns a native instance of ArrayIterator.

Example of how to walk a Array with key pairs and value:

const pairs = [
    [ 'yum', 'yam' ],
    [ 'haha', true ]
];

for (let [k, v] of pairs) {
    console.log(k, v);
}

Example running through a Array in a common way:

for (let v of [ 1, 2, 3 ]) {
    console.log(v);
}

1

This example (extracted of that original source in the OS(en)) uses the function forEach existing in objects of the type array from the Ecmascript5:

var a = ["a", "b", "c"];
a.forEach(function(entry) {
    console.log(entry);
});

-2

var i = -1; while(vetor[++i]){}

Tested in Chrome and works well !

  • 3

    If vetor[++i]has inside a false Boolean value that will not work...

Browser other questions tagged

You are not signed in. Login or sign up in order to post.