Given data similar to:
var data = [{id: 12345,
name:'my products',
items:[{
size: 'XXL',
sku: 'awe2345',
prices:[{type: 'rrp',prices: 10.99},
{type: 'sell_price', price: 9.99},
{type:'dealer', price:4.50}
]
},{
size: 'XL',
sku: 'awe2346',
prices:[{type: 'rep', prices: 10.99},
{type: 'sell_price', price: 9.99},
{type:'dealer', price:4.50}
]
}
]
}]
}]
is there a way to evaluate a string representation of an element in the data object? for example: "data[0].items[0].prices[0].rrp" ...without using eval()?
The ideal solution would be to not have the string representation in the first place. Seriously ask yourself whether you change the existing code to give you the content in a more ideal output.
However, if you can't, this should do what you want:
var path = "data[0].items[0].prices[0].rrp".split(/[\[\]\.]+/);
var next = window;
if (path[path.length - 1] == "") {
path.pop();
};
while (path.length && (next = next[path.shift()]) && typeof next == "object" && next !== null);
next;
Create a function for this:
function get(path) {
var next = window;
path = path.split(/[\[\]\.]+/);
if (path[path.length - 1] == "") {
path.pop();
};
while (path.length && (next = next[path.shift()]) && typeof next === "object" && next !== null);
return path.length ? undefined : next;
}
Downsides:
The variable data
must be in the global scope for this to work (cannot be a local variable).
It's skanky. Use it as a last resort.
Edit: To use setting functionality, you can abuse the pass-by-reference nature of JavaScript objects as follows:
function set(path, value) {
var split = Math.max(path.lastIndexOf("["), path.lastIndexOf("."));
get(path.slice(0, split))[path.slice(split + 1).replace(/\]/, "")] = value;
}
To provide some explanation of how this works:
The getter first splits the input into an array, so that each element is a member we need to traverse [data, 0, items, 0, prices, 0, rrp]
. If the search string ends with a "]", we get an extra empty-element at the end of the array, so we check for that and remove it.
We then do the big loop; so whist we have elements to traverse (while path.length
), set the next
variable to the next object member we need to traverse next = next[path.shift()]
. Check that it's an object (otherwise it wont have any members to traverse), and check that it isn't null (because typeof null == "object").
Once the loop has executed, we'll have the final element in the chain; so return it.
The setter searches for the last object reference in the search string, and retrieves that object reference using the get()
function. It then sets the returned objects key to the desired value. If we hadn't done it this way, we'd have been setting a value rather than a reference, so the "real" object would never get updated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With