recorrer - ¿Cómo hago un bucle o enumero un objeto JavaScript?




recorrer array de objetos javascript (20)

Tengo un objeto de JavaScript como el siguiente:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Ahora quiero recorrer todos los elementos p ( p1 , p2 , p3 ...) y obtener sus claves y valores. ¿Cómo puedo hacer eso?

Puedo modificar el objeto JavaScript si es necesario. Mi objetivo final es recorrer algunos pares de valores clave y, si es posible, quiero evitar el uso de eval .


Object.keys (obj): Array

recupera todas las claves con valores de cadena de todas las propiedades propias enumerables (no heredadas).

Por lo tanto, proporciona la misma lista de claves que pretende al probar cada clave de objeto con hasOwnProperty. No necesita esa operación de prueba adicional y se Object.keys( obj ).forEach(function( key ){}) que Object.keys( obj ).forEach(function( key ){}) es más rápido. Vamos a demostrarlo:

var uniqid = function(){
			var text = "",
					i = 0,
					possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
			for( ; i < 32; i++ ) {
					text += possible.charAt( Math.floor( Math.random() * possible.length ) );
			}
			return text;
		}, 
		CYCLES = 100000,
		obj = {}, 
		p1,
		p2,
		p3,
		key;

// Populate object with random properties
Array.apply( null, Array( CYCLES ) ).forEach(function(){
	obj[ uniqid() ] = new Date()
});

// Approach #1
p1 = performance.now();
Object.keys( obj ).forEach(function( key ){
	var waste = obj[ key ];
});

p2 = performance.now();
console.log( "Object.keys approach took " + (p2 - p1) + " milliseconds.");

// Approach #2
for( key in obj ) {
	if ( obj.hasOwnProperty( key ) ) {
		var waste = obj[ key ];
	}
}

p3 = performance.now();
console.log( "for...in/hasOwnProperty approach took " + (p3 - p2) + " milliseconds.");

En mi Firefox tengo los siguientes resultados.

  • El enfoque de Object.keys tomó 40.21101451665163 milisegundos.
  • para ... en / hasOwnProperty enfoque tomó 98.26163508463651 milisegundos.

PD. en Chrome la diferencia es aún mayor http://codepen.io/dsheiko/pen/JdrqXa

PS2: en ES6 (EcmaScript 2015) puede iterar mejor el objeto iterable:

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
    console.log(pair);
}

// OR 
let map = new Map([
    [false, 'no'],
    [true,  'yes'],
]);
map.forEach((value, key) => {
    console.log(key, value);
});


Aquí hay otro método para iterar a través de un objeto.

   var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};


Object.keys(p).forEach(key => { console.log(key, p[key]) })


Como es2015 se está volviendo más y más popular, estoy publicando esta respuesta que incluye el uso del generador y el iterador para iterar sin problemas entre pares [key, value] . Como es posible en otros idiomas, por ejemplo, Ruby.

Ok aquí hay un código:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function* () {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Toda la información sobre cómo puede hacer un iterador y un generador que puede encontrar en la página del desarrollador Mozilla.

Espero que haya ayudado a alguien.

EDITAR:

ES2017 incluirá Object.entries que facilitará aún más la iteración sobre pares [key, value] en objetos. Ahora se sabe que formará parte de un estándar según la información de la etapa ts39 .

Creo que es hora de actualizar mi respuesta para que se vuelva aún más fresca de lo que es ahora.

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Puede encontrar más información sobre el uso en la página de MDN


Después de revisar todas las respuestas aquí, hasOwnProperty no es necesario para mi propio uso porque mi objeto json está limpio; Realmente no tiene sentido agregar ningún procesamiento javascript adicional. Esto es todo lo que estoy usando:

for (var key in p) {
    console.log(key + ' => ' + p[key]);
    // key is key
    // value is p[key]
}

En ECMAScript 5 tiene un nuevo enfoque en los campos de iteración de literal - Object.keys

Más información se puede ver en Object.keys()

Mi elección se encuentra a continuación como una solución más rápida en las versiones actuales de los navegadores (Chrome30, IE10, FF25)

var keys = Object.keys(p),
    len = keys.length,
    i = 0,
    prop,
    value;
while (i < len) {
    prop = keys[i];
    value = p[prop];
    i += 1;
}

Puede comparar el rendimiento de este enfoque con diferentes implementaciones en jsperf.com :

Soporte de navegador que puedes ver en la tabla de compatibilidad de Kangax

Para navegador antiguo tienes polyfill simple y Object.keys()

UPD:

Comparación de rendimiento para todos los casos más populares en esta pregunta en perfjs.info :

iteración literal del objeto


Es interesante que las personas en estas respuestas hayan tocado tanto en Object.keys() como for...of pero nunca las han combinado:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

No puedes solo for...of un Object porque no es un iterador, y for...index o .forEach() ing el Object.keys() es feo / ineficiente.
Me alegra que la mayoría de las personas se abstengan de for...in (con o sin verificar .hasOwnProperty() ) ya que también es un poco desordenado, así que, aparte de mi respuesta anterior, estoy aquí para decir ...

Puedes hacer iterantes las asociaciones de objetos ordinarios! Comportarse como Map s con el uso directo de la fantasía for...of
DEMO trabajando en Chrome y FF (supongo que solo ES6)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

Mientras incluyas mi calza abajo:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

Sin tener que crear un objeto de mapa real que no tenga el azúcar sintáctico agradable.

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

De hecho, con esta cuña, si todavía desea aprovechar las otras funciones de Map (sin agregarlas todas), pero aún así desea usar la notación de objetos nítidos, ya que los objetos ahora son iterables, ¡ahora puede hacer un mapa con ellos!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

Para aquellos a los que no les guste calzar, o jugar con el prototype en general, siéntase libre de hacer la función en la ventana, llamándolo algo así como getObjIterator() entonces;

//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

Ahora solo puedes llamarlo como una función ordinaria, nada más se ve afectado

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))

o

for (let pair of getObjIterator(ordinaryObject))

No hay razón para que eso no funcione.

Bienvenido al futuro.


Los bucles pueden ser bastante interesantes cuando se utiliza JavaScript puro. Parece que solo ECMA6 (Nueva especificación de JavaScript 2015) consiguió los bucles bajo control. Desafortunadamente, mientras escribo esto, tanto los navegadores como el popular entorno de desarrollo integrado (IDE) todavía están luchando para soportar completamente las nuevas alarmas.

De un vistazo, aquí es cómo se ve un bucle de objetos JavaScript antes de ECMA6:

for (var key in object) {
  if (p.hasOwnProperty(key)) {
    var value = object[key];
    console.log(key); // This is the key;
    console.log(value); // This is the value;
  }
}

Además, sé que esto está fuera del alcance de esta pregunta, pero en 2011, ECMAScript 5.1 agregó el método forEach solo para Arrays, que básicamente creó una nueva forma mejorada para recorrer los arreglos mientras aún deja objetos no iterables con lo antiguo y confuso for loop. . Pero la parte extraña es que este nuevo método forEach no admite la break que llevó a todo tipo de otros problemas.

Básicamente, en 2011, no existe una forma sólida y real de crear un bucle en JavaScript que no sea la que muchas bibliotecas populares (jQuery, Underscore, etc.) decidieron volver a implementar.

A partir de 2015, ahora contamos con una forma mejor lista para colocar en bucle (y romper) cualquier tipo de objeto (incluidos matrices y cadenas). Aquí es cómo se verá un bucle en JavaScript cuando la recomendación se convierta en una corriente:

for (let [key, value] of Object.entries(object)) {
    console.log(key); // This is the key;
    console.log(value); // This is the value;
}

Tenga en cuenta que la mayoría de los navegadores no admitirán el código anterior a partir del 18 de junio de 2016. Incluso en Chrome, debe habilitar este indicador especial para que funcione: chrome://flags/#enable-javascript-harmony

Hasta que esto se convierta en el nuevo estándar, el método anterior aún se puede usar, pero también hay alternativas en las bibliotecas populares o incluso en alternativas ligeras para aquellos que no están usando ninguna de estas bibliotecas.


Prefacio:

  • Las propiedades del objeto pueden ser propias (la propiedad está en el objeto en sí) o heredadas (no en el objeto en sí, en uno de sus prototipos).
  • Las propiedades de los objetos pueden ser enumerables o no enumerables . Las propiedades no enumerables se quedan fuera de muchos enumeración / arrays de propiedades.
  • Los nombres de propiedades pueden ser cadenas o símbolos. Las propiedades cuyos nombres son Símbolos quedan fuera de un montón de enumeración / arrays de propiedades.

Aquí, en 2018, las opciones para recorrer en bucle las propiedades de un objeto son:

  1. for-in [ MDN , spec ]: una estructura de bucle que recorre los nombres de las propiedades enumerables de un objeto, incluidas las heredadas, cuyos nombres son cadenas
  2. Object.keys [ MDN , spec ]: una función que proporciona una matriz de los nombres de las propias propiedades enumerables de un objeto cuyos nombres son cadenas.
  3. Object.values [ MDN , spec ]: una función que proporciona una matriz de los valores de las propias propiedades enumerables de un objeto.
  4. Object.entries [ MDN , spec ]: una función que proporciona una matriz de los nombres y valores de las propiedades enumerables propias de un objeto.
  5. Object.getOwnPropertyNames [ MDN , spec ]: Una función que proporciona una matriz de los nombres de las propiedades propias de un objeto (incluso las que no se pueden enumerar) cuyos nombres son cadenas.
  6. Object.getOwnPropertySymbols [ MDN , spec ]: una función que proporciona una matriz de los nombres de las propiedades propias de un objeto (incluso las que no son enumerables) cuyos nombres son Símbolos.
  7. Reflect.ownKeys [ MDN , spec ]: Una función que proporciona una matriz de los nombres de las propiedades propias de un objeto (incluso las que no son enumerables), ya sea que esos nombres sean cadenas o símbolos.
  8. Si desea todas las propiedades de un objeto, incluidas las heredadas no enumerables, debe usar un bucle y Object.getPrototypeOf [ MDN , spec ] Y usar Object.getOwnPropertyNames , Object.getOwnPropertySymbols o Reflect.ownKeys en cada objeto en el Cadena prototipo (ejemplo en la parte inferior de esta respuesta).

Con todos ellos, excepto for-in , forEach algún tipo de construcción de bucle en la matriz ( for , for-of , forEach , etc.).

Ejemplos:

for-in

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name in o) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.keys (con un bucle for-of , pero puede usar cualquier construcción de bucle) :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.keys(o)) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.values :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const value of Object.values(o)) {
    console.log(`${value}`);
}

Object.entries :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const [name, value] of Object.entries(o)) {
    console.log(`${name} = ${value}`);
}

Object.getOwnPropertyNames :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertyNames(o)) {
    const value = o[name];
    console.log(`${name} = ${value}`);
}

Object.getOwnPropertySymbols :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Object.getOwnPropertySymbols(o)) {
    const value = o[name];
    console.log(`${String(name)} = ${value}`);
}

Reflect.ownKeys :

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (const name of Reflect.ownKeys(o)) {
    const value = o[name];
    console.log(`${String(name)} = ${value}`);
}

Todas las propiedades , incluidas las heredadas no enumerables:

// A prototype object to inherit from, with a string-named property
const p = {answer: 42};
// The object we'll look at, which inherits from `p`
const o = Object.create(p);
// A string-named property
o.question = "Life, the Universe, and Everything";
// A symbol-named property
o[Symbol("author")] = "Douglas Adams";
for (let depth = 0, current = o; current; ++depth, current = Object.getPrototypeOf(current)) {
    for (const name of Reflect.ownKeys(current)) {
        const value = o[name];
        console.log(`[${depth}] ${String(name)} = ${String(value)}`);
    }
}
.as-console-wrapper {
  max-height: 100% !important;
}


Puede usar el bucle for-in como lo muestran otros. Sin embargo, también debe asegurarse de que la clave que obtenga sea una propiedad real de un objeto y no provenga del prototipo.

Aquí está el fragmento:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}


Puedes iterar sobre él como:

for (var key in p) {
  alert(p[key]);
}

Tenga en cuenta que la key no asumirá el valor de la propiedad, es solo un valor de índice.


Tienes que usar el bucle for-in

Pero tenga mucho cuidado al usar este tipo de bucle, ya que esto hará un bucle de todas las propiedades a lo largo de la cadena del prototipo .

Por lo tanto, al usar bucles de entrada, siempre use el método hasOwnProperty para determinar si la propiedad actual en iteración es realmente una propiedad del objeto que está verificando:

for (var prop in p) {
    if (!p.hasOwnProperty(prop)) {
        //The current property is not a direct property of p
        continue;
    }
    //Do your logic with the property here
}

a través del prototipo con forEach (), que debe omitir las propiedades de la cadena del prototipo :

Object.prototype.each = function(f) {
    var obj = this
    Object.keys(obj).forEach( function(key) { 
        f( key , obj[key] ) 
    });
}


//print all keys and values
var obj = {a:1,b:2,c:3}
obj.each(function(key,value) { console.log(key + " " + value) });
// a 1
// b 2
// c 3

En ES6 tenemos símbolos conocidos para exponer algunos métodos internos previamente, puede usarlo para definir cómo funcionan los iteradores para este objeto:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    *[Symbol.iterator]() {
        yield *Object.keys(this);
    }
};

[...p] //["p1", "p2", "p3"]

Esto dará el mismo resultado que al utilizar for ... in es6 loop.

for(var key in p) {
    console.log(key);
}

¡Pero es importante saber las capacidades que ahora tiene usando es6!


En el último script de ES, puedes hacer algo como esto:

Object.entries(p);

Un objeto se convierte en un iterador cuando implementa el método .next ()

const james = {
name: 'James',
height: `5'10"`,
weight: 185,

[Symbol.iterator]() {
let properties = []
for (let key of Object.keys(james)){
     properties.push(key);
 }

index = 0;
return {
        next: () => {
            let key = properties[index];
            let value = this[key];
            let done = index >= properties.length - 1 ;
            index++;
            return { key, value, done };
        }
    };
  }

};


const iterator = james[Symbol.iterator]();

console.log(iterator.next().value); // 'James'
console.log(iterator.next().value); // `5'10`
console.log(iterator.next().value); // 185

desde ES06 puede obtener los valores de un objeto como matriz con

let arrValues = Object.values( yourObject) ;

devuelve una matriz de los valores de objeto y no extrae valores de Prototype !!

MDN DOCS Object.values ​​()

y para las llaves (ya contestadas antes que yo aquí)

let arrKeys   = Object.keys(yourObject);

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>


Haría esto en lugar de revisar obj.hasOwnerPropertydentro de cada for ... inbucle.

var obj = {a : 1};
for(var key in obj){
    //obj.hasOwnProperty(key) is not needed.
    console.log(key);
}
//then check if anybody has messed the native object. Put this code at the end of the page.
for(var key in Object){
    throw new Error("Please don't extend the native object");
}

Si desea iterar solo sobre las propiedades, use una de las respuestas anteriores, sin embargo, si desea iterar sobre todas las funciones incluidas, puede usar Object.getOwnPropertyNames(obj)

for (let o of Object.getOwnPropertyNames(Math)) {
  console.log(o);
}

A veces lo uso para probar rápidamente todas las funciones en objetos con entradas y salidas simples.


Si también desea iterar sobre propiedades no enumerables , puede utilizar Object.getOwnPropertyNames(obj)para devolver una matriz de todas las propiedades (enumerables o no) que se encuentran directamente en un objeto determinado.

var obj = Object.create({}, {
  // non-enumerable property
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});

obj.foo = 1; // enumerable property

Object.getOwnPropertyNames(obj).forEach(function (name) {
  document.write(name + ': ' + obj[name] + '<br/>');
});







each