Skip to content

Instantly share code, notes, and snippets.

@sphvn
Last active October 26, 2023 21:49
Show Gist options
  • Star 45 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save sphvn/dcdf9d683458f879f593 to your computer and use it in GitHub Desktop.
Save sphvn/dcdf9d683458f879f593 to your computer and use it in GitHub Desktop.
Recursively traverse object javascript, recurse json js, loop and get key/value pair for JSON
var traverse = function(o, fn) {
for (var i in o) {
fn.apply(this,[i,o[i]]);
if (o[i] !== null && typeof(o[i])=="object") {
traverse(o[i], fn);
}
}
}
// usage
var obj = {'your':'object'};
traverse(obj, function(k,v){
console.log(k + " : " + v);
});
@orlaqp
Copy link

orlaqp commented Jul 16, 2018

Simple Awesome!!! Thanks!

Here is a small modification (Typescript) in case someone finds it useful also

export function traverse(o: any, fn: (obj: any, prop: string, value: any) => void) {
    for (const i in o) {
        fn.apply(this, [o, i, o[i]]);
        if (o[i] !== null && typeof(o[i]) === 'object') {
            traverse(o[i], fn);
        }
    }
}

@ms0124
Copy link

ms0124 commented Oct 1, 2019

ممنون

thanks ;-)

@rmkane
Copy link

rmkane commented Mar 23, 2020

I modified this to track scope.

const traverse = function(o, fn, scope = []) {
  for (let i in o) {
    fn.apply(this, [i, o[i], scope]);
    if (o[i] !== null && typeof o[i] === "object") {
      traverse(o[i], fn, scope.concat(i));
    }
  }
}

traverse(myObject, (key, value, scope) => {
  if (value === 'Some Value') {
    console.log(`Position: myObject[${scope.concat(key).map(k => isNaN(k) ? `'${k}'` : k).join('][')}]`);
  }
});

@Tyler-V
Copy link

Tyler-V commented Sep 22, 2020

These are great, thanks!

@stefanpl
Copy link

Thanks everyone for putting this up!

Some adjustments I made:

  • use Object.entries, to avoid iterating the prototype chain
  • don't expose scope to the outside world
  • minor TypeScript adjustments
  • variables renamed for humans
export type TraverseFunction<T> = (
  obj: T,
  prop: string,
  value: unknown,
  scope: string[]
) => void;

export const traverseObject = <T = Record<string, unknown>>(
  object: T,
  fn: TraverseFunction<T>
): void => traverseInternal(object, fn, []);

const traverseInternal = <T = Record<string, unknown>>(
  object: T,
  fn: TraverseFunction<T>,
  scope: string[] = []
): void => {
  Object.entries(object).forEach(([key, value]) => {
    fn.apply(this, [object, key, value, scope]);
    if (value !== null && typeof value === "object") {
      traverseInternal(value, fn, scope.concat(key));
    }
  });
};

@blaasvaer
Copy link

And when taking nested arrays into account?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment