3

I ran into a problem when I was trying to access a property of an index of a global array by using a string. I have dynamically generated string that looks something like this:

var foo = "arr[0].prp[0].prp[1]"

The index in the array and how deep it is, is dynamic and I'm just providing an example of what it may look like.

Now the problem is when I try to use this string to get a property like this, it fails:

foo.something, foo["something"], window[foo].something or window[foo]["something"]

I can however use eval() to get it to work, but I would really like to get away without having to use it.

Anyone have any suggestions or ideas?

br4n_d0n
  • 31
  • 2
  • first thing that came to my mind, was eval. – Johan Jun 08 '13 at 20:30
  • 1
    That's what's eval is for, actually. Still wondering how exactly is this string generated; turning it into an array of accessors would at least allow sane alternatives. – raina77ow Jun 08 '13 at 20:30
  • Why do you have that in a string? What's this for? – elclanrs Jun 08 '13 at 20:32
  • For those wondering, the string is generated from clicking on an item from a list of many items. Then I grab what id the item has and construct a string based on that in order to access an array that contains info about all of the items in the list. – br4n_d0n Jun 08 '13 at 20:42
  • directly access `something` instead of holding expression in string format, like this `window["arr"][0]["prp"][0]["prp"][1]["something"]`. it will surely work. – Zain Shaikh Jun 08 '13 at 20:47

3 Answers3

1

Using eval can be a bad idea, so I'll provide an alternate solution. If you provided how the string is generated, you may be able to save having to parse it and re-write the generator instead.

You have a string generated that looks like

var foo = "arr[0].prp[0].prp[1]";

What happens if you use some RegExp like this /\[\d+\]|\..*?(?=[\.\[])/ig ?

var m = foo.match(/\[\d+\]|\..*?(?=[\.\[])|^.*?(?=[\.\[])/ig);
// ["arr", "[0]", ".prp", "[0]", ".prp", "[1]"]

Just needs a little more parsing

m = m.map(function (e) {
    if (e.charAt(0) === '.') return e.slice(1);
    else if (e.charAt(0) === '[') return e.slice(1, -1);
    else return e
});
// ["arr", "0", "prp", "0", "prp", "1"]

Now you can loop over it

var o = window, i;
for (i = 0; i < m.length; ++i) {
    o = o[m[i]];
}
// o is now the result of window.arr[0].prp[0].prp[1]
Paul S.
  • 64,864
  • 9
  • 122
  • 138
  • Thanks, you and @flav have provided me with some good ideas about parsing my string. Side note, I will have to look more into regular expressions as I'm really a noob when it comes to them. – br4n_d0n Jun 08 '13 at 20:59
1

*Live Demo*

var part = {
    "arr": [
        {
            "prp": [
                {
                    "prp": [
                        "result"
                     ]
                }
            ]
        }
    ]
};
var foo = "arr[0].prp[0].prp[0]";

function getValue(obj, chain) {
    var keys = chain.split('\.'),
        iterable = [];
    for (var i = 0, len = keys.length; i < len; i++) {
        var parts = keys[i].split('[');
        parts[1] = parts[1].replace('\]', '');
        iterable.push(parts[0], parts[1]);
    }
    target = obj[iterable[0]];

    for (var j = 1, len = iterable.length; j < len; j++) {
        target = target[iterable[j]];
    };
    return target;
};
flavian
  • 28,161
  • 11
  • 65
  • 105
1

One more approach:

    var obj = {
        arr: [{
            prp: [{
                prp: ['a', 'b', 'c']
            }]
        }]
    };
    var foo = "arr[0].prp[0].prp[1]";

    var path = foo.replace(/\]/g, "").replace(/\[/g, ".").split('.').reverse();
    var res = obj;
    while (path.length && res){
        var el = path.pop();
        res = res[el];
    }

    console.log(res);
claustrofob
  • 5,448
  • 2
  • 19
  • 22