Javascript foreach loop en objeto de matriz asociativa

182

¿Por qué mi bucle for-each no itera sobre mi objeto de matriz asociativa de JavaScript?

// defining an array
var array = [];

// assigning values to corresponding keys
array["Main"] = "Main page";
array["Guide"] = "Guide page";
array["Articles"] = "Articles page";
array["Forum"] = "Forum board";

// expected: loop over every item,
// yet it logs only "last" assigned value - "Forum"
for (var i = 0; i < array.length; i++) {
    console.log(array[i]);
}

EDITAR: jQuery each() podría ser útil: https://api.jquery.com/jQuery.each/

Szymon Toda
fuente
1
Crea una matriz pero luego la usa como un mapa. Parece que quieres un objeto plano en su lugar.
Jon
44
No hay cosas como associative arraysen JS: es una matriz simple o un objeto. Nada impide agregar propiedades no numéricas Array, pero eso no lo hace associative, en particular, la lengthpropiedad no contará automáticamente estas propiedades.
raina77ow
3
re: No hay tales cosas como matrices asociativas en JS. - redactado de otra manera: JavaScript usa el nombre "Objeto" en lugar del nombre "matriz asociativa". Pero no tiene una propiedad ".length".
Jesse Chisholm

Respuestas:

315

La .lengthpropiedad solo rastrea propiedades con índices numéricos (claves). Estás usando cadenas para las teclas.

Puedes hacerlo:

var arr_jq_TabContents = {}; // no need for an array

arr_jq_TabContents["Main"] = jq_TabContents_Main;
arr_jq_TabContents["Guide"] = jq_TabContents_Guide;
arr_jq_TabContents["Articles"] = jq_TabContents_Articles;
arr_jq_TabContents["Forum"] = jq_TabContents_Forum;

for (var key in arr_jq_TabContents) {
    console.log(arr_jq_TabContents[key]);
}

Para estar seguro, es una buena idea en bucles como ese asegurarse de que ninguna de las propiedades sean resultados inesperados de la herencia:

for (var key in arr_jq_TabContents) {
  if (arr_jq_TabContents.hasOwnProperty(key))
    console.log(arr_jq_TabContents[key]);
}

editar : probablemente sea una buena idea tener en cuenta que la Object.keys()función está disponible en los navegadores modernos y en el Nodo, etc. Esa función devuelve las teclas "propias" de un objeto, como una matriz:

Object.keys(arr_jq_TabContents).forEach(function(key, index) {
  console.log(this[key]);
}, arr_jq_TabContents);

La función de devolución de llamada pasada .forEach()se llama con cada clave y el índice de la clave en la matriz devuelta por Object.keys(). También pasó la matriz a través de la cual la función está iterando, pero esa matriz no es realmente útil para nosotros; Necesitamos el objeto original . Se puede acceder a eso directamente por su nombre, pero (en mi opinión) es un poco mejor pasarlo explícitamente, lo que se hace pasando un segundo argumento al .forEach()objeto original, que se vinculará como thisdentro de la devolución de llamada. (Acabo de ver que esto se observó en un comentario a continuación).

Puntiagudo
fuente
Qué es esto var arr_jq_TabContents = {};? Quiero decir {}
Szymon Toda
1
@Ultra es un objeto vacío literal. Simplemente significa que la variable se inicializa con una referencia a un nuevo objeto vacío.
Puntiagudo
@Ultra no necesita una instancia de matriz porque en ese código no la está utilizando como una matriz de JavaScript. JavaScript no tiene "matrices asociativas" como algunos otros lenguajes.
Puntiagudo
1
¿Cuál es la diferencia entre asignar []y {}? ¿Solo los diferentes prototipos?
SoonDead
8
En lugar de usar hasOwnProperty, debería ser posible en todos los navegadores web modernos iterar sobre las claves de un objeto usando: Object.keys(arr_jq_TabContents).forEach( function(key) { ... } );
Gregory Bell
80

Este es un enfoque muy simple. La ventaja es que también puede obtener claves:

for (var key in array) {
    var value = array[key];
    console.log(key, value);
}

Para ES6:

array.forEach(value => {
  console.log(value)
})  

Para ES6: (si desea valor, índice y la matriz en sí)

array.forEach((value, index, self) => {
  console.log(value, index, self)
})  
tika
fuente
12
No lo use varen bucles que sugieran un alcance que no existe. Use varen frente del bucle o leten el bucle.
ceving
2
@ceving, ¿puedes explicar más sobre por qué no usar var en los bucles? Vengo de C ++ / PHP y no entiendo esto. el alcance existe en el bucle, pero es temporal, por lo que no estoy seguro de lo que quiere decir.
Dennis
66
@Dennis En la mayoría de los idiomas, una declaración de variable en un forbucle genera un alcance limitado al cuerpo del forbucle. Pero en JavaScript, una variable declarada por varsiempre es una función global, incluso si la escribe en un forbucle. Ver aquí: davidwalsh.name/for-and-against-let
ceving el
1
no pérdidas de memoria per se, sino definitivamente "derrames de memoria". varen Javascript crea variables en la memoria incluso después de que se completa el ciclo.
ahnbizcad
Creo que el punto de estos comentarios con respecto al uso de "var" es usar ahora "let" en general, pero específicamente en un bucle. Las razones se explican anteriormente, pero en resumen se debe al alcance, "var" crea un alcance global.
DeeZone
6

Ya hay algunos ejemplos sencillos, pero me doy cuenta de cómo redactó su pregunta que probablemente proviene de un fondo PHP y espera que JavaScript funcione de la misma manera, no es así. Un PHP arrayes muy diferente de un JavaScriptArray .

En PHP, una matriz asociativa puede hacer la mayor parte de lo que puede hacer una matriz indexada numéricamente (las array_*funciones funcionan, puedecount() , etc.) Simplemente cree una matriz y comience a asignar índices de cadena en lugar de numéricos.

En JavaScript, todo es un objeto (excepto las primitivas: cadena, numérico, booleano), y las matrices son una implementación determinada que le permite tener índices numéricos. Cualquier cosa empujado a una matriz afectará a su length, y puede ser iterado sobre el uso de métodos Array ( map, forEach, reduce, filter,find , etc.) Sin embargo, como todo es un objeto, que está siempre libre para asignar propiedades simplemente, porque eso es algo que se hace a cualquier objeto La notación de corchetes es simplemente otra forma de acceder a una propiedad, por lo que en su caso:

array['Main'] = 'Main Page';

en realidad es equivalente a:

array.Main = 'Main Page';

Según su descripción, supongo que desea una 'matriz asociativa', pero para JavaScript, este es un caso simple de usar un objeto como un mapa hash. Además, sé que es un ejemplo, pero evite nombres sin sentido que solo describan el tipo de variable (por ejemplo array) y el nombre en función de lo que debe contener (por ejemplo pages). Los objetos simples no tienen muchas buenas formas directas de iterar, por lo que a menudo los convertiremos primero en matrices utilizando Objectmétodos ( Object.keysen este caso, también hay entriesy valuesse agregarán a algunos navegadores en este momento) que podemos recorrer.

// assigning values to corresponding keys
const pages = {
  Main: 'Main page',
  Guide: 'Guide page',
  Articles: 'Articles page',
  Forum: 'Forum board',
};

Object.keys(pages).forEach((page) => console.log(page));
Josh de Qaribou
fuente
4

arr_jq_TabContents[key] ve la matriz como una forma de índice 0.

MSO
fuente
4

Aquí hay una manera simple de usar una matriz asociativa como un tipo de objeto genérico:

Object.prototype.forEach = function(cb){
   if(this instanceof Array) return this.forEach(cb);
   let self = this;
   Object.getOwnPropertyNames(this).forEach(
      (k)=>{ cb.call(self, self[k], k); }
   );
};

Object({a:1,b:2,c:3}).forEach((value, key)=>{ 
    console.log(`key/value pair: ${key}/${value}`);
});

Chouettou
fuente
1

Esto es (esencialmente) incorrecto en la mayoría de los casos:

var array = [];
array["Main"] = "Main page";

Eso crea una propiedad no elemento en la matriz con el nombre Main . Aunque las matrices son objetos, normalmente no desea crear propiedades que no sean elementos en ellas.

Si desea indexar arraypor esos nombres, normalmente usaría unMap objeto simple o simple, no una matriz.

Con un Map(ES2015 +), al que llamaré mapporque soy creativo:

let map = new Map();
map.set("Main", "Main page");

A continuación, iterar utilizando los iteradores de sus values, keys, o entriesmétodos, por ejemplo:

for (const value of map.values()) {
    // Here, `value` will be `"Main page"`, etc.
}

Usando un objeto simple, que llamaré creativamente obj:

let obj = Object.create(null); // Creates an object with no prototype
obj.Main = "Main page"; // Or: `obj["Main"] = "Main page";`

que había entonces iterar sus contenidos utilizando Object.keys, Object.valueso Object.entries, por ejemplo:

for (const value of Object.values(proches_X)) {
    // Here, `value` will be `"Main page"`, etc.
}
TJ Crowder
fuente
0

var obj = {
  no: ["no", 32],
  nt: ["no", 32],
  nf: ["no", 32, 90]
};

count = -1; // which must be static value
for (i in obj) {
  count++;
  if (obj.hasOwnProperty(i)) {
    console.log(obj[i][count])
  };
};

en este código, utilicé el método de paréntesis para los valores de llamada en la matriz porque contenía la matriz, sin embargo, brevemente, la idea de que una variable i tiene una clave de propiedad y con un bucle llamado ambos valores de la matriz asociada

Método perfecto, si está interesado, presione como

Dev-Wb Ahmed
fuente
No está haciendo un bucle a través de una matriz, está haciendo un bucle a través de un objeto que tiene matrices en sus claves. Lea la pregunta y mire el ejemplo.
Pedro Joaquín
0

Puedes hacerlo

var array = [];

// assigning values to corresponding keys
array[0] = "Main page";
array[1] = "Guide page";
array[2] = "Articles page";
array[3] = "Forum board";


array.forEach(value => {
    console.log(value)
})
Shuvro
fuente