6

In this stackoverflow thread, i learnt you can get a object path via a simple string.

Accessing nested JavaScript objects with string key

consider the following:

var person = { name: "somename", personal: { weight: "150", color: "dark" }};

var personWeight = deep_value(person,"personal.weight");

I an trying to construct an array of the object values who are not of type 'object' from my 'person' object.

Hence the array would look like:

[['name', []],['personal.weight', []],['personal.color', []]];

I want them to look in that form because i have further use for it down the road.

That's what I've tried:

var toIterate = { name: "somename", personal: { age: "19", color: "dark" } }

var myArray = [];

$.each(toIterate, recursive);

function recursive(key, value) {         

    if (key !== null) {
        myArray.push([key, []]);
    }
    else {
        $.each(value, recursive);
    }
}

console.log(myArray);
Community
  • 1
  • 1
TotalWar
  • 335
  • 1
  • 6
  • 16
  • Why to pass the specific property `personal.weight` if your result will have all other properties? – DontVoteMeDown Aug 21 '15 at 13:22
  • im not sure what do you mean there. – TotalWar Aug 21 '15 at 13:29
  • If I got you right, you want a new func to produce that result, which has nothing to do with the func `deep_value`, actually? – DontVoteMeDown Aug 21 '15 at 13:35
  • that is correct.I would like a function to produce a string path representation of an object that i will feed to the deep_value function.I will post the answer that i figured out, its not very efficient mind you. – TotalWar Aug 21 '15 at 13:43
  • In fact, that is not correct. All what concerns to your question should in the main post, so as your code. I have added your code to your main qustion, you should remove that answer. – DontVoteMeDown Aug 21 '15 at 17:40

4 Answers4

11

Just use recursion to walk the object.

var person = {
    name: "somename",
    personal: {
        weight: "150",
        color: "dark",
        foo: {
            bar: 'bar',
            baz: 'baz'
        },
        empty: {
        }
    }
};

// however you want to do this
var isobject = function(x){
    return Object.prototype.toString.call(x) === '[object Object]';
};

var getkeys = function(obj, prefix){
    var keys = Object.keys(obj);
    prefix = prefix ? prefix + '.' : '';
    return keys.reduce(function(result, key){
        if(isobject(obj[key])){
            result = result.concat(getkeys(obj[key], prefix + key));
        }else{
            result.push(prefix + key);
        }
        return result;
    }, []);
};

var keys = getkeys(person);

document.body.innerHTML = '<pre>' + JSON.stringify(keys) + '</pre>';

Then use Array.prototype.map to massage the array of keys into your preferred format. Note the behaviour with person.personal.empty.

This does seem like a strange way to store an object's keys. I wonder what your 'further use for it down the road' is.

1983
  • 5,882
  • 2
  • 27
  • 39
2

This is what worked for me. Note that, a raw map is created first and then mapped to an join the items in the Array with ..

var toIterate = {
  name: "somename",
  personal: {
    age: "19",
    color: "dark"
  }
};

console.log(getObjPath(toIterate).map(item => item.join('.')));

function isObject(x) {
  return Object.prototype.toString.call(x) === '[object Object]';
};

function getObjPath(obj, pathArray, busArray) {
  pathArray = pathArray ? pathArray : [];
  if (isObject(obj)) {
    for (key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (isObject(obj[key])) {
          busArray = busArray ? bussArray : [];
          busArray.push(key);
          getObjPath(obj[key], pathArray, busArray);
        } else {
          if (busArray) {
            pathArray.push(busArray.concat([key]));
          } else {
            pathArray.push([key]);
          }
        }
      }
    }
  }
  return pathArray;
}

Good Luck...

Aakash
  • 21,375
  • 7
  • 100
  • 81
0

I found the following solution on github.

https://github.com/mariocasciaro/object-path

TotalWar
  • 335
  • 1
  • 6
  • 16
0

I believe that the sole existence of the topic linked in the question is originated from string paths in dot notation.

However if in the first place you have to resolve all the paths then you can totally eliminate the string dot notation relieving yourself from unnecessary work.

Assuming that your schema is in the form of

const obj = { name: "somename", personal: { weight: "150", color: "dark" }};

then it would be ideal to collect the paths in an array like

const paths = [["name"], ["personal","weight"], ["personal","color"]]

so that obtaining any nested value is now a piece of cake. Like;

paths[1].reduce((value,path) => value[path], obj); // 150

Let's see in action.

function keyPaths(schema, ...keys){
  return Object.keys(schema)
               .reduce( (r,k) => ( typeof schema[k] === "object" ? r.push(...keyPaths(schema[k],...keys,k))
                                                                 : r.push([...keys,k])
                                 , r
                                 )
                      , []          
                      );                         
}

const obj    = { name: "somename", personal: { weight: "150", color: "dark" }},
      paths  = keyPaths(obj),
      result = paths[1].reduce((value,path) => value[path], obj);

console.log(JSON.stringify(paths,""));
console.log(result);
Redu
  • 25,060
  • 6
  • 56
  • 76