问题
The following function does an amazing job of retrieving a deep object key value with a dot notated string:
function getPathValue(obj, path) {
return new Function('_', 'return _.' + path)(obj);
}
For example, it returns the value for a key like "bar" using the following as the path argument:
'data.abc.foo.bar'
However, some API's pack additional stringified JSON into some key values.
I'm looking for an enhancement to the above function that will handle that case.
For example, Stack's own WebSocket service:
wss://qa.sockets.stackexchange.com/
returns strings like this:
{"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"stackoverflow.com\",\"id\":53819390,\"titleEncodedFancy\":\"Should I start with webGL1 or webGL2 when using Three.js\",\"bodySummary\":\"Spent some time learning and understanding the basics of webGL and I'm now diving into Three.js.\\n\\nI noticed that I have the option of using webGL1 or webGL2. Seems as if webGL1 is the default, however ...\",\"tags\":[\"three.js\",\"webgl\"],\"lastActivityDate\":1545064508,\"url\":\"https://stackoverflow.com/questions/53819390/should-i-start-with-webgl1-or-webgl2-when-using-three-js\",\"ownerUrl\":\"https://stackoverflow.com/users/8226111/romanrogers\",\"ownerDisplayName\":\"romanrogers\",\"apiSiteParameter\":\"stackoverflow\"}"}
And I'd like to be able to use the above function to retrieve values with an input string like:
'data.bodySummary'
Perhaps the input string could look something like:
'data/bodySummary'
where the solidus (/slash) represents a JSON.parse().
Note, this needs to be dynamic as I'd like to make it where the end user can select arbitrary keys to return values for in the general case.
回答1:
You could check if the item from where you take a property is a string an perform a parsing. The return the value of the property.
function getValue(object, path) {
return path
.split('.')
.reduce((o, k) => (typeof o === 'string' ? JSON.parse(o) : o)[k], object);
}
var data = {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"stackoverflow.com\",\"id\":53819390,\"titleEncodedFancy\":\"Should I start with webGL1 or webGL2 when using Three.js\",\"bodySummary\":\"Spent some time learning and understanding the basics of webGL and I'm now diving into Three.js.\\n\\nI noticed that I have the option of using webGL1 or webGL2. Seems as if webGL1 is the default, however ...\",\"tags\":[\"three.js\",\"webgl\"],\"lastActivityDate\":1545064508,\"url\":\"https://stackoverflow.com/questions/53819390/should-i-start-with-webgl1-or-webgl2-when-using-three-js\",\"ownerUrl\":\"https://stackoverflow.com/users/8226111/romanrogers\",\"ownerDisplayName\":\"romanrogers\",\"apiSiteParameter\":\"stackoverflow\"}"};
console.log(getValue(data, 'data.bodySummary'));
ES5
function getValue(object, path) {
return path
.split('.')
.reduce(function (o, k) {
return (typeof o === 'string' ? JSON.parse(o) : o)[k];
}, object);
}
var data = {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"stackoverflow.com\",\"id\":53819390,\"titleEncodedFancy\":\"Should I start with webGL1 or webGL2 when using Three.js\",\"bodySummary\":\"Spent some time learning and understanding the basics of webGL and I'm now diving into Three.js.\\n\\nI noticed that I have the option of using webGL1 or webGL2. Seems as if webGL1 is the default, however ...\",\"tags\":[\"three.js\",\"webgl\"],\"lastActivityDate\":1545064508,\"url\":\"https://stackoverflow.com/questions/53819390/should-i-start-with-webgl1-or-webgl2-when-using-three-js\",\"ownerUrl\":\"https://stackoverflow.com/users/8226111/romanrogers\",\"ownerDisplayName\":\"romanrogers\",\"apiSiteParameter\":\"stackoverflow\"}"};
console.log(getValue(data, 'data.bodySummary'));
回答2:
Here's a function that takes an object or a JSON string as it's first param, a key path string or array as it's second param, and recursively walks the object with the key path.
let object = {"action":"155-questions-active","data":"{\"siteBaseHostAddress\":\"stackoverflow.com\",\"id\":53819390,\"titleEncodedFancy\":\"Should I start with webGL1 or webGL2 when using Three.js\",\"bodySummary\":\"Spent some time learning and understanding the basics of webGL and I'm now diving into Three.js.\\n\\nI noticed that I have the option of using webGL1 or webGL2. Seems as if webGL1 is the default, however ...\",\"tags\":[\"three.js\",\"webgl\"],\"lastActivityDate\":1545064508,\"url\":\"https://stackoverflow.com/questions/53819390/should-i-start-with-webgl1-or-webgl2-when-using-three-js\",\"ownerUrl\":\"https://stackoverflow.com/users/8226111/romanrogers\",\"ownerDisplayName\":\"romanrogers\",\"apiSiteParameter\":\"stackoverflow\"}"};
function asObject(str) {
try {
return JSON.parse(str);
} catch (e) {
return str;
}
}
function valueAtKeyPath(o, path) {
o = asObject(o);
if (typeof path === 'string') path = path.split('.');
if (!o || !path.length) return o;
return valueAtKeyPath(o[path[0]], path.slice(1));
}
console.log(valueAtKeyPath(object, 'action'))
console.log(valueAtKeyPath(object, 'data.id'))
来源:https://stackoverflow.com/questions/53819904/access-deep-object-member-of-embeded-json