I have a json object like this:
var obj = {
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
This JSON can be any valid JSON. Now I want to access and update some property based on an array available to me like this:
['glossary', 'GlossDiv', 'GlossList', 'GlossEntry', 'SortAs'] // any dynamic but valid path
So given the above array, I want to access
obj['glossary']['GlossDiv']['GlossList']['GlossEntry']['SortAs']
so that I can update its value. I have config(or any such json)
as an instance variable, so I want to directly update that rather than creating a new json and then replacing the entire config
object. I have access to jQuery, underscore, backbone and of course plain old JS.
You could reduce the object with walking the path.
function getValue(object, path) { return path.reduce(function (o, k) { return (o || {})[k]; }, object); } var object = { glossary: { title: "example glossary", GlossDiv: { title: "S", GlossList: { GlossEntry: { ID: "SGML", SortAs: "SGML", GlossTerm: "Standard Generalized Markup Language", Acronym: "SGML", Abbrev: "ISO 8879:1986", GlossDef: { para: "A meta-markup language, used to create markup languages such as DocBook.", GlossSeeAlso: ["GML", "XML"] }, GlossSee: "markup" } } } } }; console.log(getValue(object, ['glossary', 'GlossDiv', 'GlossList', 'GlossEntry', 'SortAs']));
Though you are using Underscore, Lodash is 100% compatible with Backbone and can replace Underscore and it offers _.get
and _.set
for your specific case.
The path can be in an array or it can be a string. It even handles accessing array indexes.
_.get(object, path, [defaultValue])
var object = { 'a': [{ 'b': { 'c': 3 } }] }; _.get(object, 'a[0].b.c'); // => 3 _.get(object, ['a', '0', 'b', 'c']); // => 3 _.get(object, 'abc', 'default'); // => 'default'
_.set
creates missing objects and arrays along the path if they do not exist.
_.set(object, path, value)
_.set(object, 'a[0].b.c', 4); console.log(object.a[0].bc); // => 4 _.set(object, ['x', '0', 'y', 'z'], 5); console.log(object.x[0].yz); // => 5
There's even a _.result
function which calls the value if it's a function.
_.result(object, path, [defaultValue])
var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; _.result(object, 'a[0].b.c1'); // => 3 _.result(object, 'a[0].b.c2'); // => 4 _.result(object, 'a[0].b.c3', 'default'); // => 'default' _.result(object, 'a[0].b.c3', _.constant('default')); // => 'default'
Based on Nina's answer , to set the value, you could do something like the following, having a path which stops at before the last key, and use the last key to update the object manually.
function getValue(object, path) { return path.reduce(function (o, k) { return (o || {})[k]; }, object); } var obj = { "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": { "para": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML"] }, "GlossSee": "markup" } } } } }; var target = getValue(obj, ['glossary', 'GlossDiv']); target.title = "test"; console.log(obj);
Or as a new function, which takes a value directly and does all the job.
function setValue(object, path, value) { var target = path.slice(0, -1).reduce(function(obj, key) { return (obj || {})[key]; }, object); target[path[path.length-1]] = value; } var obj = { "glossary": { "title": "example glossary", "GlossDiv": { "title": "S", "GlossList": { "GlossEntry": { "ID": "SGML", "SortAs": "SGML", "GlossTerm": "Standard Generalized Markup Language", "Acronym": "SGML", "Abbrev": "ISO 8879:1986", "GlossDef": { "para": "A meta-markup language, used to create markup languages such as DocBook.", "GlossSeeAlso": ["GML", "XML"] }, "GlossSee": "markup" } } } } }; setValue(obj, ['glossary', 'GlossDiv', 'GlossList', 'GlossEntry', 'GlossSee'], "my test value"); console.log(obj);
Nina's answer would be my preferred way of doing this. For those not yet familiar with functional programming or reducing, a simple forEach will do the trick. Good for comparison.
var config = {
name: "foo",
email: "bar",
photo: {
small: "somelink",
large: "largelink"
}
};
var keys = ['photo', 'large'];
var prevRef = config, ref;
keys.forEach(function(val, index) {
console.log(val);
ref = prevRef[val];
prevRef = ref;
});
console.log(ref);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.