recorrer un objeto (árbol) de forma recursiva

Resuelto Val asked hace 14 años • 5 respuestas

¿Hay alguna manera (en jQuery o JavaScript) de recorrer cada objeto y sus hijos y nietos, etc.?

Si es así... ¿puedo leer también su nombre?

Ejemplo:

foo :{
  bar:'',
  child:{
    grand:{
      greatgrand: {
        //and so on
      }
    }
  }
}

entonces el bucle debería hacer algo como esto...

loop start
   if(nameof == 'child'){
     //do something
   }
   if(nameof == 'bar'){
     //do something
   }
   if(nameof =='grand'){
     //do something
   }
loop end
Val avatar Mar 31 '10 06:03 Val
Aceptado

Estás buscando el for...inbucle:

for (var key in foo)
{
    if (key == "child")
        // do something...
} 

Tenga en cuenta que for...inlos bucles iterarán sobre cualquier propiedad enumerable, incluidas aquellas que se agregan al prototipo de un objeto. Para evitar actuar sobre estas propiedades, puede usar el hasOwnPropertymétodo para verificar si la propiedad pertenece solo a ese objeto:

for (var key in foo)
{
    if (!foo.hasOwnProperty(key))
        continue;       // skip this property
    if (key == "child")
        // do something...
}

Realizar el bucle de forma recursiva puede ser tan sencillo como escribir una función recursiva:

// This function handles arrays and objects
function eachRecursive(obj)
{
    for (var k in obj)
    {
        if (typeof obj[k] == "object" && obj[k] !== null)
            eachRecursive(obj[k]);
        else
            // do something... 
    }
}
Andy E avatar Mar 30 '2010 23:03 Andy E

Puede tener una función recursiva de bucle de objetos con una función de ejecución de propiedad propExecincorporada.

function loopThroughObjRecurs (obj, propExec) {
  for (var k in obj) {
    if (typeof obj[k] === 'object' && obj[k] !== null) {
      loopThroughObjRecurs(obj[k], propExec)
    } else if (obj.hasOwnProperty(k)) {
      propExec(k, obj[k])
    }
  }
}

Prueba aquí:

// I use the foo object of the OP
var foo = {
  bar:'a',
  child:{
    b: 'b',
    grand:{
      greatgrand: {
        c:'c'
      }
    }
  }
}

function loopThroughObjRecurs (obj, propExec) {
  for (var k in obj) {
    if (typeof obj[k] === 'object' && obj[k] !== null) {
      loopThroughObjRecurs(obj[k], propExec)
    } else if (obj.hasOwnProperty(k)) {
      propExec(k, obj[k])
    }
  }
}

// then apply to each property the task you want, in this case just console
loopThroughObjRecurs(foo, function(k, prop) {
  console.log(k + ': ' + prop)
})
Expandir fragmento

João Pimentel Ferreira avatar Apr 19 '2019 15:04 João Pimentel Ferreira

Si desea recuperar un árbol de relaciones, puede utilizar Object.keys de forma recursiva.

function paths(item) {
  function iter(r, p) {
    var keys = Object.keys(r);
    if (keys.length) {
      return keys.forEach(x => iter(r[x], p.concat(x)));
    }
    result.push(p);
  }
  var result = [];
  iter(item, []);
  return result;
}

var data = {
  foo: {
    bar: '',
    child: {
      grand: {
        greatgrand: {}
      }
    }
  }
};

console.log(paths(data));
Expandir fragmento

Esto se puede ampliar para buscar valores dentro de una estructura de objeto que coincidan con una función:

function objectSearch(rootItem, matcher) {
  const visited = [];
  const paths = [];
  function iterate(item, path) {
    if (visited.includes(item)) {
      return;
    }
    visited.push(item);
    if (typeof item === "object" && item !== null) {
      var keys = Object.keys(item);
      if (keys.length) {
        return keys.forEach(key => iterate(item[key], path.concat(key)));
      }
    }
    if (matcher(item)) {
      paths.push(path);
    }
  }
  iterate(rootItem, []);
  return paths;
}
function searchForNaNs(rootItem) {
  return objectSearch(rootItem, (v) => Object.is(NaN, v));
}
var banana = {
  foo: {
    bar: "",
    child: {
      grand: {
        greatgrand: {},
        nanan: "NaN",
        nan: NaN,
      },
    },
  },
};
console.log("There's a NaN at", searchForNaNs(banana)[0].join("."), "in this object:", banana);
Expandir fragmento

Rick avatar Jun 27 '2017 15:06 Rick

Considere usar escaneo de objetos . Es poderoso para el procesamiento de datos una vez que lo entiendes.

Una gran ventaja es que los elementos se recorren en orden de "eliminación segura". Entonces, si elimina uno, no arruinará el ciclo. Y tienes acceso a muchas otras propiedades como padres, etc.

// const objectScan = require('object-scan');

const obj = { foo: { bar: '', child: { grand: { greatgrand: { /* and so on */ } } } } };

objectScan(['**'], {
  filterFn: ({ property }) => {
    console.log(property);
  }
})(obj);
// => greatgrand
// => grand
// => child
// => bar
// => foo
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>
Expandir fragmento

Descargo de responsabilidad : soy el autor de escaneo de objetos

vincent avatar Oct 24 '2020 16:10 vincent