web-dev-qa-db-fra.com

parcourir une carte en javascript

J'ai une structure comme celle-ci:

var myMap = {
    partnr1: ['modelA', 'modelB', 'modelC'],
    partnr2: ['modelA', 'modelB', 'modelC']
};

Je vais parcourir chacun des éléments (partnr) avec leurs associatifs (modèles).

J'essaie une double $ chaque itération pour y parvenir, mais rien ne se passe:

$.each(myMap, function (i, val) {
    $.each(i, function (innerKey, innerValue) {

        setTimeout(function () {
            $('#variant').fadeOut("slow", function () {
                $(this).text(innerKey + "-" + innerValue).fadeIn("slow");

            });

        }, i * 6000);

    });
});

L’effet de fondu en entrée et en sortie que j’essaie d’obtenir fonctionne bien lorsque vous utilisez un tableau de valeurs unique (Object), mais pas lorsque j’ai besoin d’avoir plus d’une valeur pour chaque clé comme ici.

Avez-vous des idées sur la façon de réaliser cette itération et existe-t-il d'autres moyens que d'utiliser une carte qui serait mieux dans ce cas?

Toutes les suggestions seraient d'intérêt.

14
user2374903

J'utiliserais le javascript standard:

for (var m in myMap){
    for (var i=0;i<myMap[m].length;i++){
    ... do something with myMap[m][i] ...
    }
} 

Notez les différentes façons de traiter les objets et les tableaux.

27
Atle

Le rappel à $.each() reçoit le nom de la propriété et la valeur, dans cet ordre. Vous essayez donc de parcourir les noms de propriétés dans l'appel interne à $.each(). Je pense que tu veux:

$.each(myMap, function (i, val) {
  $.each(val, function(innerKey, innerValue) {
    // ...
  });
});

Dans la boucle interne, dans un objet tel que votre carte, les valeurs sont des tableaux. C'est bon, mais notez que les valeurs "innerKey" seront toutes des nombres.

edit - Maintenant, une fois que c'est réglé, voici le problème suivant:

    setTimeout(function () {

      // ...

    }, i * 6000);

La première fois dans cette boucle, "i" sera la chaîne "partnr1". Ainsi, cette tentative de multiplication donnera NaN. Vous pouvez conserver un compteur externe pour suivre le nombre de propriétés de la carte externe:

var pcount = 1;
$.each(myMap, function(i, val) {
  $.each(val, function(innerKey, innerValue) {
    setTimeout(function() {
      // ...
    }, pcount++ * 6000);
  });
});
3
Pointy

N'utilisez pas les itérateurs pour le faire. Maintenez votre propre boucle en incrémentant un compteur dans le rappel et en appelant l'opération de manière récursive sur l'élément suivant.

$.each(myMap, function(_, arr) {
    processArray(arr, 0);
});

function processArray(arr, i) {
    if (i >= arr.length) return;

    setTimeout(function () {
        $('#variant').fadeOut("slow", function () {
            $(this).text(i + "-" + arr[i]).fadeIn("slow");

            // Handle next iteration
            processArray(arr, ++i);
        });
    }, 6000);
}

Bien qu'il y ait une erreur de logique dans votre code. Vous définissez le même conteneur sur plusieurs valeurs différentes (à peu près au même moment). Peut-être que vous voulez dire pour chacun de mettre à jour son propre conteneur.

1
user1106925

Une réponse à votre question de 2019:

Cela dépend de la version de ECMAScript que vous utilisez.

Pre ES6:

Utilisez l'une des réponses ci-dessus

Pour ES6 (ES 2015):

Vous devez utiliser un objet Map, qui possède la fonction entries():

var myMap = new Map();
myMap.set("0", "foo");
myMap.set(1, "bar");
myMap.set({}, "baz");

for (const [key, value] of myMap.entries()) {
  console.log(key, value);
}

Pour ES8 (ES 2017):

Object.entries() a été introduit:

const object = {'a': 1, 'b': 2, 'c' : 3};
for (const [key, value] of Object.entries(object)) {
  console.log(key, value);
}
1
David Nathan