1

I'm wondering if its possible to retrieve all paths a javascript object contains

Example:

obj = {
  prop1 : {
    x: 19
    y: 43
  }
  prop2 : {
    another: {
      here: 1
    }
  }
  prop3: "hello"
}

Where the result would be an array with following elements:

Result: ["prop1.x", "prop1.y", "prop2.another.here", "prop3"]

Is this possible?

Thanks!

  • possible duplicate of [Recursively looping through an object to build a property list](http://stackoverflow.com/questions/15690706/recursively-looping-through-an-object-to-build-a-property-list) – Artyom Neustroev Mar 08 '15 at 17:57

2 Answers2

3
function flattenKeys(obj, delimiter) {
    delimiter = delimiter || '.';

    return recurse(obj, '', []);

    function recurse(obj, path, result) {
        if (typeof obj === "object") {
            Object.keys(obj).forEach(function (key) {
                recurse(obj[key], path + delimiter + key, result);
            });
        } else {
            result.push(path.slice(delimiter.length));
        }
        return result;
    }
}

used as

var obj = {
  prop1 : {
    x: 19,
    y: 43
  },
  prop2 : {
    another: {
      here: 1
    }
  },
  prop3: "hello"
};

flattenKeys(obj);

// -> ["prop1.x", "prop1.y", "prop2.another.here", "prop3"]

Alternative implementation without string operations:

function flattenKeys(obj, delimiter) {
    delimiter = delimiter || '.';

    return recurse(obj, [], []);

    function recurse(obj, path, result) {
        if (typeof obj === "object") {
            Object.keys(obj).forEach(function (key) {
                path.push(key);
                recurse(obj[key], path, result);
                path.pop();
            });
        } else {
            result.push(path.join(delimiter));
        }
        return result;
    }
}
Tomalak
  • 332,285
  • 67
  • 532
  • 628
  • Great work! Some "benchmarks": http://jsfiddle.net/jkoudys/w49rcp40/ (Might be wrong tho :)) – Per Arne Andersen Mar 08 '15 at 20:52
  • Did you paste the wrong link? That's just my jsfiddle. – Josh from Qaribou Mar 08 '15 at 21:17
  • You are right, wrong link: http://jsfiddle.net/w49rcp40/2/. Seems like its browser dependant. They are both excellent ;) – Per Arne Andersen Mar 08 '15 at 21:57
  • 1
    Tweaked this one abit for my needs, Excuse the Hipsterscript tho: http://jsfiddle.net/SKMpV/435/... It can now get properties from complex types, and has a depth limit for Circular control. – Per Arne Andersen Mar 08 '15 at 22:00
  • Hint: `level` is `path.length`. – Tomalak Mar 09 '15 at 05:12
  • Oh and hint 2: There is jsperf.com, you don't have to use jsFiddle for measuring performance. http://jsperf.com/retrieve-path-of-object-items – Tomalak Mar 09 '15 at 07:11
  • Besides the fact that you could have used `path.length` to begin with, there's a bug in [your implementation](http://jsfiddle.net/SKMpV/435/): You do `level++` but you never do `level--`. Implicitly correct would have been `recurse obj[key], path, result, level + 1`, in which case you would not need to manually increment or decrement at all. – Tomalak Mar 09 '15 at 15:50
2

Wrote this while Tomalak was putting together here. Recursion's the obvious approach for doing this.

var inputObject = {
    prop1: {
        x: 19,
        y: 43
    },
    prop2: {
        another: {
            here: 1
        }
    },
    prop3: "hello"
};

function getProps(obj) {
  var props = [];

  var findPropsRecursive = function (robj, str) {
    robj = robj || {};
    var keys = Object.keys(robj);
    if (keys.length > 0 && (robj instanceof Object)) {
      return keys.map(function (key) {
        return findPropsRecursive(robj[key], str + (str ? '.' : '') + key);
      });
    } else {
      props.push(str);
      return '';
    }
  };

  findPropsRecursive(obj, '');

  return props;
}

console.log(getProps(inputObject));

on jsfiddle: http://jsfiddle.net/jkoudys/w49rcp40/

Josh from Qaribou
  • 6,776
  • 2
  • 23
  • 21
  • There's a bug in your code, Internet Explorer reveals it: `TypeError: Object.keys: argument is not an Object`. – Tomalak Mar 09 '15 at 07:19
  • 1
    Object.keys is not supported in < IE9 :) – Per Arne Andersen Mar 09 '15 at 15:28
  • That's what polyfills are for. btw if you want to follow their example, Google apps only does an n-1 support statement for IE, and since the latest stable is IE11, even 9 is out of support. Personally I tend to do n-2, but IE8 would be n-3 -- old enough to just put up a 'your browser isn't supported' page, though I typically wait until n-4 for that. n-3 is usually just best-effort. – Josh from Qaribou Mar 10 '15 at 01:12
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys#Polyfill – Josh from Qaribou Mar 10 '15 at 01:12
  • @JoshfromQaribou That is not what I'm talking about. Read the error message again. It happens in IE11 as well. (When `Object.keys` is missing on a platform then that's not a bug in your code.) – Tomalak Mar 10 '15 at 07:27
  • @Tomalak that reply was to Per Arne, not you. – Josh from Qaribou Mar 10 '15 at 13:25