I am trying to write a javascript recursive function that receives one parameter - nested JSON object.
The function goes through the potentially infinitely nested object and converts all the keys (property names) to a string that is stored in array. Array is returned to a place where the function was called.
Example of JSON object:
{
OBJECT1: {
ATTRIBUTE3: {
PARAMETER2: {
PROPERTY1: {
}
}
}
}
}
The object does not hold any values.
What i tried and did not work:
function convertKeysToString(obj) {
let keys = [];
for (let key in obj) {
if (typeof obj[key] === 'object') {
keys = keys.concat(convertKeysToString(obj[key]));
} else {
keys.push(key.toString());
}
}
return keys;
}
As a result, I expected that returned key is pushed to an array, but the funciton didnt get the key at all or was not pushed to keys array.
Another code I tried:
function getNestedObjectKeys(obj) {
var keys = []
var firstLevel = null
var property = Object.keys(obj)
property = property[0]
firstLevel = Object.keys(obj[property])[0]
if (firstLevel == undefined) {
return 0
}
let returnedValue = keys.unshift(getNestedObjectKeys(obj[property]))
if (returnedValue == 0) {
return Object.keys(obj[property])[0]
}
returnedValue = Object.keys(obj[property])[0]
if (returnedValue != obj[property[0]]) {
return Object.keys(obj[property])[0]
}
else if (returnedValue == firstLevel) {
return keys
}
}
The function should return the key name and push (unshift) it to string and then return it, but the unshift doesnt do what I expect and in the returnedValue is not a expected returned string.
I approached it the way that the function findd the deepest (empty) object, and starts returning the name of the key. The thing is that I must return the key name AND push it to the string, which I can't find the way to accomplish at once.
Your first solution is pretty close, but has one problem (well, one main problem): when the value is type object, you don't add its key to the array. So how is it supposed to get into the array? Give this a shot:
function convertKeysToString(obj) {
let keys = [];
for (let key in obj) {
keys.push(key.toString());
if (typeof obj[key] === 'object') {
keys = keys.concat(convertKeysToString(obj[key]));
}
}
return keys;
}
Other things you may want to consider:
typeof null is object.
typeof [] is also object.
You could have a look to object, which are truthy and typeof object.
const
getKeys = object => (keys => [
...keys.flatMap(key => object[key] && typeof object[key] === 'object'
? [key, ...getKeys(object[key])]
: [key]
)
])(Object.keys(object)),
data = { OBJECT1: { ATTRIBUTE3: { PARAMETER2: { PROPERTY1: {} } } } },
result = getKeys(data);
console.log(result);
var obj = {
name: "Simon",
age: "20",
clothing: {
style: "simple",
hipster: false
}
}
for(var propt in obj){
console.log(propt + ': ' + obj[propt]);
}
How does the variable propt represent the properties of the object? It's not a built-in method or property. Why does it come up with every property in the object?
Iterating over properties requires this additional hasOwnProperty check:
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
// do stuff
}
}
It's necessary because an object's prototype contains additional properties for the object which are technically part of the object. These additional properties are inherited from the base object class, but are still properties of obj.
hasOwnProperty simply checks to see if this is a property specific to this class, and not one inherited from the base class.
It's also possible to call hasOwnProperty through the object itself:
if (obj.hasOwnProperty(prop)) {
// do stuff
}
But this will fail if the object has an unrelated field with the same name:
var obj = { foo: 42, hasOwnProperty: 'lol' };
obj.hasOwnProperty('foo'); // TypeError: hasOwnProperty is not a function
That's why it's safer to call it through Object.prototype instead:
var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo'); // true
As of JavaScript 1.8.5 you can use Object.keys(obj) to get an Array of properties defined on the object itself (the ones that return true for obj.hasOwnProperty(key)).
Object.keys(obj).forEach(function(key,index) {
// key: the name of the object key
// index: the ordinal position of the key within the object
});
This is better (and more readable) than using a for-in loop.
Its supported on these browsers:
Firefox (Gecko): 4 (2.0)
Chrome: 5
Internet Explorer: 9
See the Mozilla Developer Network Object.keys()'s reference for futher information.
Girls and guys we are in 2019 and we do not have that much time for typing... So lets do this cool new fancy ECMAScript 2016:
Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));
In up-to-date implementations of ES, you can use Object.entries:
for (const [key, value] of Object.entries(obj)) { }
or
Object.entries(obj).forEach(([key, value]) => ...)
If you just want to iterate over the values, then use Object.values:
for (const value of Object.values(obj)) { }
or
Object.values(obj).forEach(value => ...)
It's the for...in statement (MDN, ECMAScript spec).
You can read it as "FOR every property IN the obj object, assign each property to the PROPT variable in turn".
It's just a for...in loop. Check out the documentation at Mozilla.
if (typeof obj === 'object' && obj !== null) {
Object.keys(obj).forEach(key => {
console.log("\n" + key + ": " + obj[key]);
});
}
// *** Explanation line by line ***
// Explaining the bellow line
// It checks if obj is neither null nor undefined, which means it's safe to get its keys.
// Otherwise it will give you a "TypeError: Cannot convert undefined or null to object" if obj is null or undefined.
// NOTE 1: You can use Object.hasOwnProperty() instead of Object.keys(obj).length
// NOTE 2: No need to check if obj is an array because it will work just fine.
// NOTE 3: No need to check if obj is a string because it will not pass the 'if typeof obj is Object' statement.
// NOTE 4: No need to check if Obj is undefined because it will not pass the 'if type obj is Object' statement either.
if (typeof obj === 'object' && obj !== null) {
// Explaining the bellow line
// Just like in the previous line, this returns an array with
// all keys in obj (because if code execution got here, it means
// obj has keys.)
// Then just invoke built-in javascript forEach() to loop
// over each key in returned array and calls a call back function
// on each array element (key), using ES6 arrow function (=>)
// Or you can just use a normal function ((key) { blah blah }).
Object.keys(obj).forEach(key => {
// The bellow line prints out all keys with their
// respective value in obj.
// key comes from the returned array in Object.keys(obj)
// obj[key] returns the value of key in obj
console.log("\n" + key + ": " + obj[key]);
});
}
If your environment supports ES2017 then I would recommend Object.entries:
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`);
});
As shown in Mozillas Object.entries() documentation:
The Object.entries() method returns an array of a given object's own
enumerable property [key, value] pairs, in the same order as that
provided by a for...in loop (the difference being that a for-in loop
enumerates properties in the prototype chain as well).
Basically with Object.entries we can forgo the following extra step that is required with the older for...in loop:
// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
// do stuff
}
Dominik's answer is perfect, I just prefer to do it that way, as it's cleaner to read:
for (var property in obj) {
if (!obj.hasOwnProperty(property)) continue;
// Do stuff...
}
jquery allows you to do this now:
$.each( obj, function( key, value ) {
alert( key + ": " + value );
});
The for...in loop represents each property in an object because it is just like a for loop. You defined propt in the for...in loop by doing:
for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}
A for...in loop iterates through the enumerable properties of an object. Whichever variable you define, or put in the for...in loop, changes each time it goes to the next property it iterates. The variable in the for...in loop iterates through the keys, but the value of it is the key's value. For example:
for(var propt in obj) {
console.log(propt);//logs name
console.log(obj[propt]);//logs "Simon"
}
You can see how the variable differs from the variable's value. In contrast, a for...of loop does the opposite.
I hope this helps.
To add ES2015's usage of Reflect.ownKeys(obj) and also iterating over the properties via an iterator.
For example:
let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };
can be iterated over by
// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));
If you would like to iterate directly over the values of the keys of an object, you can define an iterator, just like JavaScipts's default iterators for strings, arrays, typed arrays, Map and Set.
JS will attempt to iterate via the default iterator property, which must be defined as Symbol.iterator.
If you want to be able to iterate over all objects you can add it as a prototype of Object:
Object.prototype[Symbol.iterator] = function*() {
for(p of Reflect.ownKeys(this)){ yield this[p]; }
}
This would enable you to iterate over the values of an object with a for...of loop, for example:
for(val of obj) { console.log('Value is:' + val ) }
Caution: As of writing this answer (June 2018) all other browsers, but IE, support generators and for...of iteration via Symbol.iterator
The above answers are a bit annoying because they don't explain what you do inside the for loop after you ensure it's an object: YOU DON'T ACCESS IT DIRECTLY! You are actually only delivered the KEY that you need to apply to the OBJ:
var obj = {
a: "foo",
b: "bar",
c: "foobar"
};
// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
// We check if this key exists in the obj
if (obj.hasOwnProperty(someKey))
{
// someKey is only the KEY (string)! Use it to get the obj:
var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"
// NOW you can treat it like an obj
var shouldBeBar = myActualPropFromObj.b;
}
}
This is all ECMA5 safe. Even works in the lame JS versions like Rhino ;)
let obj = {"a": 3, "b": 2, "6": "a"}
Object.keys(obj).forEach((item) => {console.log("item", obj[item])})
// a
// 3
// 2
You can access the nested properties of the object using the for...in and forEach loop.
for...in:
for (const key in info) {
console.log(info[key]);
}
forEach:
Object.keys(info).forEach(function(prop) {
console.log(info[prop]);
// cities: Array[3], continent: "North America", images: Array[3], name: "Canada"
// "prop" is the property name
// "data[prop]" is the property value
});
You can use Lodash. The documentation
var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
...
});
Object.keys(obj).forEach(key =>
console.log(`key=${key} value=${obj[key]}`)
);
Nowadays you can convert a standard JS object into an iterable object just by adding a Symbol.iterator method. Then you can use a for of loop and acceess its values directly or even can use a spread operator on the object too. Cool. Let's see how we can make it:
var o = {a:1,b:2,c:3},
a = [];
o[Symbol.iterator] = function*(){
var ok = Object.keys(this);
i = 0;
while (i < ok.length) yield this[ok[i++]];
};
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);
Your for loop is iterating over all of the properties of the object obj. propt is defined in the first line of your for loop. It is a string that is a name of a property of the obj object. In the first iteration of the loop, propt would be "name".
Objects in JavaScript are collections of properties and can therefore be looped in a for each statement.
You should think of obj as an key value collection.
If running Node I'd recommend:
Object.keys(obj).forEach((key, index) => {
console.log(key);
});
While the top-rated answer is correct, here is an alternate use case i.e if you are iterating over an object and want to create an array in the end. Use .map instead of forEach
const newObj = Object.keys(obj).map(el => {
//ell will hold keys
// Getting the value of the keys should be as simple as obj[el]
})
I want to add to the answers above, because you might have different intentions from Javascript. A JSON object and a Javascript object are different things, and you might want to iterate through the properties of a JSON object using the solutions proposed above, and then be surprised.
Suppose that you have a JSON object like:
var example = {
"prop1": "value1",
"prop2": [ "value2_0", "value2_1"],
"prop3": {
"prop3_1": "value3_1"
}
}
The wrong way to iterate through its 'properties':
function recursivelyIterateProperties(jsonObject) {
for (var prop in Object.keys(example)) {
console.log(prop);
recursivelyIterateProperties(jsonObject[prop]);
}
}
You might be surprised of seeing the console logging 0, 1, etc. when iterating through the properties of prop1 and prop2 and of prop3_1. Those objects are sequences, and the indexes of a sequence are properties of that object in Javascript.
A better way to recursively iterate through a JSON object properties would be to first check if that object is a sequence or not:
function recursivelyIterateProperties(jsonObject) {
for (var prop in Object.keys(example)) {
console.log(prop);
if (!(typeof(jsonObject[prop]) === 'string')
&& !(jsonObject[prop] instanceof Array)) {
recursivelyIterateProperties(jsonObject[prop]);
}
}
}
What for..in loop does is that it creates a new variable (var someVariable) and then stores each property of the given object in this new variable(someVariable) one by one. Therefore if you use block {}, you can iterate. Consider the following example.
var obj = {
name:'raman',
hobby:'coding',
planet:'earth'
};
for(var someVariable in obj) {
//do nothing..
}
console.log(someVariable); // outputs planet
Here I am iterating each node and creating meaningful node names. If you notice, instanceOf Array and instanceOf Object pretty much does the same thing (in my application, i am giving different logic though)
function iterate(obj,parent_node) {
parent_node = parent_node || '';
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
var node = parent_node + "/" + property;
if(obj[property] instanceof Array) {
//console.log('array: ' + node + ":" + obj[property]);
iterate(obj[property],node)
} else if(obj[property] instanceof Object){
//console.log('Object: ' + node + ":" + obj[property]);
iterate(obj[property],node)
}
else {
console.log(node + ":" + obj[property]);
}
}
}
}
note - I am inspired by Ondrej Svejdar's answer. But this solution has better performance and less ambiguous
Also adding the recursive way:
function iterate(obj) {
// watch for objects we've already iterated so we won't end in endless cycle
// for cases like var foo = {}; foo.bar = foo; iterate(foo);
var walked = [];
var stack = [{obj: obj, stack: ''}];
while(stack.length > 0)
{
var item = stack.pop();
var obj = item.obj;
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
// check if we haven't iterated through the reference yet
var alreadyFound = false;
for(var i = 0; i < walked.length; i++)
{
if (walked[i] === obj[property])
{
alreadyFound = true;
break;
}
}
// new object reference
if (!alreadyFound)
{
walked.push(obj[property]);
stack.push({obj: obj[property], stack: item.stack + '.' + property});
}
}
else
{
console.log(item.stack + '.' + property + "=" + obj[property]);
}
}
}
}
}
Usage:
iterate({ foo: "foo", bar: { foo: "foo"} });
You basically want to loop through each property in the object.
JSFiddle
var Dictionary = {
If: {
you: {
can: '',
make: ''
},
sense: ''
},
of: {
the: {
sentence: {
it: '',
worked: ''
}
}
}
};
function Iterate(obj) {
for (prop in obj) {
if (obj.hasOwnProperty(prop) && isNaN(prop)) {
console.log(prop + ': ' + obj[prop]);
Iterate(obj[prop]);
}
}
}
Iterate(Dictionary);
To further refine the accepted answer it's worth noting that if you instantiate the object with a var object = Object.create(null) then object.hasOwnProperty(property) will trigger a TypeError. So to be on the safe side, you'd need to call it from the prototype like this:
for (var property in object) {
if (Object.prototype.hasOwnProperty.call(object, property)) {
// do stuff
}
}
Check type
You can check how propt represent object propertis by
typeof propt
to discover that it's just a string (name of property). It come up with every property in the object due the way of how for-in js "build-in" loop works.
var obj = {
name: "Simon",
age: "20",
clothing: {
style: "simple",
hipster: false
}
}
for(var propt in obj){
console.log(typeof propt, propt + ': ' + obj[propt]);
}
If you just want to iterate to map property values then lodash has _.mapValues
const obj = {
a: 2,
b: 3
}
const res = _.mapValues(obj, v => v * 2)
console.log(res)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>
I am working with an object where I need to preserve the order of the entries, even though some keys are alphanumeric and others are integers. (Yes, I know.)
The object I'm starting with looks like this:
{
a: 'the',
quick: 'quick',
b: 'brown',
fox: 'fox'
}
After manipulation, the object should look like this:
{
a: 'the',
0: 'quick',
b: 'brown',
1: 'fox'
}
But. Because iteration order in javascript objects differs from insertion order (integers are iterated first), if I go about this straightforwardly, I won't get the correctly ordered result:
let myReindexedObject = {};
myReindexedObject['a'] = 'the';
myReindexedObject['0'] = 'quick';
myReindexedObject['b'] = 'brown';
myReindexedObject['1'] = 'fox';
console.log(myReindexedObject);
I've tried to solve this issue by building a Map (which, unlike an object, preserves entry order) which I can then convert into an object.
Source: (I adapted this gist by Luke Horvat: Convert ES6 Map to Object Literal .)
Can you guess what happens?
let myMap = new Map();
myMap.set('a', 'the');
myMap.set('0', 'quick');
myMap.set('b', 'brown');
myMap.set('1', 'fox');
let myArray = Array.from(myMap);
let myReindexedObject = myArray.reduce((myReindexingObject, [key, value]) => {
return Object.assign(myReindexingObject, { [key]: value })
}, {});
console.log(myReindexedObject);
Is there any way I can use integer-based keys like 0 and 1 and still preserve the object entries in a custom order?
Or do I need to consider other approaches?
In the process of writing the question above, it suddenly occurred to me as I was typing:
(integers are iterated first)
that what a javascript engine recognises as an integer and what humans recognise as a number are, of course, not the same.
To any human, these two:
1
1.
are not typographically identical, but they are pretty much equivalent.
To any javascript interpreter, they are entirely distinct: the first is an integer; the second is not.
Working Example:
let myReindexedObject = {};
myReindexedObject['a'] = 'the';
myReindexedObject['0.'] = 'quick';
myReindexedObject['b'] = 'brown';
myReindexedObject['1.'] = 'fox';
console.log(myReindexedObject);
If the javascript interpreter needs to identify these indexes, it can do so, using the regex:
/d+\./
and, once identified, if it needs to know the integer that the string corresponds to, it can use:
parseInt(myIndex);
I will use this approach for now.
If anyone can suggest a better approach, I will be happy to upvote and accept.
We can define our own object, that keeps track of properties. And by intercepting required features we can make it work.
Using Proxy it's easily achievable:
// DEMO
let o = new CoolObject();
o['a'] = 'the';
o['0'] = 'quick';
o['b'] = 'brown';
o['1'] = 'fox';
o['c'] = 'jumped';
delete o['c'];
console.log('Object.keys: ', Object.keys(o));
console.log('JSON.stringify: ', JSON.stringify(o));
console.log('console.log: ', o);
console.log('Object.getOwnPropertyNames: ', Object.getOwnPropertyNames(o));
console.log('obj.propertyIsEnumerable("keys"): ', o.propertyIsEnumerable('keys'));
console.log('obj.propertyIsEnumerable("a"): ', o.propertyIsEnumerable('a'));
<script src="https://cdn.jsdelivr.net/gh/OnkarRuikar/temp#main/CoolObject.js"></script>
See console logs for output.
Note the insertion ordered property names. Result of getOwnPropertyNames are also insertion ordered except methods.
The CoolObject class definition:
(function () {
// original functions
let _keys = Object.keys;
let _getOwnPropertyNames = Object.getOwnPropertyNames;
let _defineProperty = Object.defineProperty;
let _stringify = JSON.stringify;
let _log = console.log;
// main feature definition
let CoolObject = function () {
let self = this;
let handler = {
_coolKeys: [],
set(target, key, val) {
let keys = this._coolKeys;
if (!keys.some(k => k === key))
keys.push(key);
target[key] = val;
},
get(target, key) {
return target[key];
},
keys() {
return this._coolKeys.slice(0);
},
deleteProperty(target, key) {
let keys = this._coolKeys;
const index = keys.indexOf(key);
if (index > -1) {
keys.splice(index, 1);
}
delete target[key];
},
defineProperty(obj, prop, val) {
let keys = this._coolKeys;
if (!keys.some(k => k === prop))
keys.push(prop);
_defineProperty(self, prop, val);
},
getOwnPropertyNames(obj) {
let props = _getOwnPropertyNames(obj);
return [...new Set([...this._coolKeys, ...props])];
},
// many improvements can be done here
// you can use your own modified pollyfill
stringifyHelper(obj, replacer, space) {
let out = '{';
for (let key of this._coolKeys) {
out += `"${key}":${_stringify(obj[key], replacer, space)}, `;
}
out += '}';
return out;
},
};
_defineProperty(self, 'keys', { value: () => handler.keys() });
_defineProperty(self, 'getOwnPropertyNames', { value: (o) => handler.getOwnPropertyNames(o) });
_defineProperty(self, 'stringify', { value: (...args) => handler.stringifyHelper(...args) });
return new Proxy(self, handler);
} // CoolObject end
// ----- wrap inbuilt objects -----
Object.keys = function (obj) {
if (!(obj instanceof CoolObject))
return _keys(obj);
return obj.keys();
}
Object.defineProperty = function (obj, prop, val) {
if (!(obj instanceof CoolObject))
_defineProperty(...arguments);
obj.defineProperty(...arguments);
}
Object.getOwnPropertyNames = function (obj) {
if (!(obj instanceof CoolObject))
return _getOwnPropertyNames(obj);
return obj.getOwnPropertyNames(obj);
}
JSON.stringify = function (obj, replacer, indent) {
if (!(obj instanceof CoolObject))
return _stringify(...arguments);
return obj.stringify(...arguments);
}
console.log = function () {
let myArgs = [];
for (let arg of arguments) {
if (arg instanceof CoolObject) {
let keys = arg.keys();
arg = Object.assign({}, arg);
for (let key of keys) {
arg[`.${key}`] = arg[key]
delete arg[key];
}
}
myArgs.push(arg);
}
_log(...myArgs);
}
window.CoolObject = CoolObject;
})();
The handler object maintains property names in _coolKeys array. And tracks addition and deletion operations. To make object behave like an original Object we need to wrap some inbuilt APIs, like Object.keys().
Note: for the demo I've implemented bare minimum rough code. Many improvements can be done. You can intercept more inbuilt APIs as per your requirements.
Let´s assume I have an object property which is passed into a function. In this case 'name' is filled with 'myObject.name' (which has the value 'Tom') - so basically 'Tom' gets passed into the function as the 'name'
function(name) {
do something //non-essential for my question
}
Is it possible to get the object, where 'Tom' is the property of, just by having the information 'Tom'? Basically I´m looking to get myObject.
Thanks :)
No, that's not possible.
All that the function knows is that one of its parameters was pointed to the string "Tom", not what else points to that string somewhere else in memory.
You can store objects within an array, filter the array to match property name of object to parameter passed to function using for..of loop, Object.entries(), which returns an array of property, values of an object.
const data = Array();
const setObjectPropertyName = _name => {
data.push({[_name]:_name});
return data
}
const getObjectByPropertyName = prop => {
let res = `${prop} property not found in data`;
for (let obj of data) {
for (let [key] of Object.entries(obj)) {
if(key === prop) return obj;
}
}
return res;
}
let s = setObjectPropertyName("Tom");
let g = getObjectByPropertyName("Tom");
let not = getObjectByPropertyName("Tome");
console.log(s,"\n", g, "\n", not);
Disclaimer: you absolutely should not do this. I'm only posting this because it is in fact possible (with some caveats), just really not advisable.
Going on the assumption that this is running in the browser and it's all running in the global scope (like in a script tag), you could technically iterate over the window object, check any objects in window for a name property and determine if their name property matches the name passed to your function.
var myObject = {
name: 'Tom',
thisIs: 'so awful',
imSorry: true,
};
function doSomethingWithName(name) {
for (var obj in window) {
var tmp = window[obj];
if (Object(tmp) === tmp && tmp.name === name) {
return tmp;
}
}
}
console.log(doSomethingWithName(myObject.name));
I've got a object like this:
{"status":200,
"success":true,
"result": [ {"Description":"", "Year":"", "Price/STK":"", "Main Cat":"Fruits"} ]
}
I have distinct lists I need to use, and the Price key can be: Price/STK, Price/Box, Price/Btl or Price.
I know I can get the value using, for example, data.result['Price/STK'], but I don't want to check every key, I'd like to search for the price and just use.
How would I determine if a word ('Price*', for example) is part of a key and get that value?
There's no built in way to do this, you have to iterate and check each key.
You could just create a convenient function :
function matchKey(objectToSearch, keyToFind) {
for (var k in objectToSearch) {
if ( k.toLowerCase().indexOf(keyToFind.toLowerCase()) !== -1)
return objectToSearch[k];
}
return null;
}
matchKey({year : 2015, "Price/STK" : "value"}, "price"); // returns "value"
FIDDLE
You could solve this problem easily using lodash (or underscore)
_.findKey(obj, function(key) { return _.startsWith(key, 'Price')})
This finds the first key that starts with price.
You can get the property names of an object using Object.keys, and then use indexOf to search for a value, but it does an exact match and doesn't take a regular expression as an argument.
So you have to loop over all the property names until you find the one you want. There are built–in iterators to help:
var obj = {"status":200,
"success":true,
"result": [ {"Description":"desc",
"Year":"yr",
"Price/STK":"price/stk",
"Main Cat":"Fruits"}
]
};
function getValueLike(obj, prop){
var re = new RegExp('^' + prop);
var value;
Object.keys(obj).some(function(prop) {
if (re.test(prop)) {
value = obj[prop];
return true;
}
});
return value;
}
document.write(getValueLike(obj.result[0], 'Price')); // price/stk
A version that uses indexOf on the property name might be faster and is a little less code:
function getValueLike(obj, prop){
var value;
Object.keys(obj).some(function(key) {
if (key.indexOf(prop) == 0) {
value = obj[key];
return true;
}
});
return value;
}
which can be reduced to:
function getValueLike(obj, prop, value){
Object.keys(obj).some(function(key) {return key.indexOf(prop) == 0 && ((value = obj[key]) || true)});
return value;
}
which also allows a default value to be passed to value, but it's a little too obfuscated for me.
Using an arrow function:
function getValueLike(obj, prop, value){
Object.keys(obj).some(key => key.indexOf(prop) == 0 && ((value = obj[key]) || true));
return value;
}
Filter the set of keys on the result array's object for "Price", and then return the value associated with that. I made a function for it as an example.
function selectPrice(obj){
return obj.result[0][
Object.keys(obj.result[0]).filter(function(el){
return el.indexOf("Price") > -1
})[0]
]
}
var data = {"status":200,
"success":true,
"result": [ {"Description":"", "Year":"", "Price/STK":"6", "Main Cat":"Fruits"} ]
};
document.write(selectPrice(data));