I have already reviewed some of the answers to similar questions, however, I want to ask my question differently.
Let's say we have a string like "level1.level2.level3. ..." that indicates a nested property in an object called Obj.
The point is that we may not know how many nested properties exist in this string. For instance, it may be "level1.level2" or "level1.level2.level3.level4".
Now, I want to write a function, that given the Obj and the string of properties as input, to simply tell us if such a nested property exists in the object or not (let's say true or false as output).
Update: Thanks to @Silvinus, I found the solution with a minor modification:
private checkNestedProperty(obj, props) {
var splitted = props.split('.');
var temp = obj;
for (var index in splitted) {
if (temp[splitted[index]] === 'undefined' || !temp[splitted[index]]) return false;
temp = temp[splitted[index]];
}
return true;
}
-
@Pedram, you want to get "report" about existence of each property or just for the most(last) nested one?RomanPerekhrest– RomanPerekhrest2016年05月04日 06:39:28 +00:00Commented May 4, 2016 at 6:39
-
@RomanPerekhrest In fact, the most (last) one. However, it is obvious that if each of these properties does not exist, the last one does not exist as well :)Pedram– Pedram2016年05月04日 06:45:23 +00:00Commented May 4, 2016 at 6:45
-
I am wondering why my question should get a down vote!Pedram– Pedram2016年05月04日 07:27:05 +00:00Commented May 4, 2016 at 7:27
4 Answers 4
You could use Array#every()
and thisArg
of it, by iterating the keys and checking if it is in the given object.
var fn = function (o, props) {
return props.split('.').every(k => k in o && (o = o[k], true));
}
console.log(fn({}, "toto.tata")); // false
console.log(fn({ toto: { tata: 17 } }, "toto.tata")); // true
console.log(fn({ toto: { tata: { tutu: 17 } } }, "toto.foo.tata")); // false
console.log(fn({ toto: { tata: false } }, "toto.tata")); // true
-
1does not work if value of a key is falsy, or null.
console.log(fn({ toto: { tata: false } }, "toto.tata")); // false
Morlo Mbakop– Morlo Mbakop2022年01月22日 13:54:22 +00:00Commented Jan 22, 2022 at 13:54 -
@MorloMbakop, thank you for the hint. now it should work as expected. please see edit.Nina Scholz– Nina Scholz2022年01月22日 13:59:38 +00:00Commented Jan 22, 2022 at 13:59
-
Looks lovely like ost of your answers, although i don't understand it.Morlo Mbakop– Morlo Mbakop2022年01月22日 14:12:33 +00:00Commented Jan 22, 2022 at 14:12
You can explore your Obj with this function :
var fn = function(obj, props) {
var splited = props.split('.');
var temp = obj;
for(var index in splited) {
if(typeof temp[splited[index]] === 'undefined') return false;
temp = temp[splited[index]]
}
return true
}
var result = fn({ }, "toto.tata");
console.log(result); // false
var result = fn({ toto: { tata: 17 } }, "toto.tata");
console.log(result); // true
var result = fn({ toto: { tata: { tutu: 17 } } }, "toto.foo.tata");
console.log(result); // false
This function allow to explore nested property of Obj that depends of props passed in parameter
-
This answer fails on the case
fn({a:false}, 'a')
. Minor point, but there is no need for the variabletemp
here.user663031– user6630312016年05月04日 06:23:10 +00:00Commented May 4, 2016 at 6:23 -
Also, shouldn't it be
temp = temp[splited[index]];
? For that reason, the test casefn({a: {b: { c: 1 }}}, 'a.b.c')
causes a run-time error "Cannot read property 'c' of undefined".user663031– user6630312016年05月04日 06:29:46 +00:00Commented May 4, 2016 at 6:29 -
For the first comment, ... I agree. I write this code so fast. I edited it and change my test by if(typeof temp[splited[index]] === 'undefined') return false; For the second, sorry it's a mistake. temp = obj[splited[index]] must be replace by temp = temp[splited[index]]Silvinus– Silvinus2016年05月04日 06:48:33 +00:00Commented May 4, 2016 at 6:48
-
@Silvinus Thank you, I have modified your answer (minor mistake) and put the correct function in my update.Pedram– Pedram2016年05月04日 06:54:43 +00:00Commented May 4, 2016 at 6:54
This answer provides the basic answer to your question. But it needs to be tweaked to handle the undefined case:
function isDefined(obj, path) {
function index(obj, i) {
return obj && typeof obj === 'object' ? obj[i] : undefined;
}
return path.split(".").reduce(index, obj) !== undefined;
}
-
why downvote? downvoter, how about some explanation?! Or, maybe, you're just clicking without arguments ?RomanPerekhrest– RomanPerekhrest2016年05月04日 06:58:30 +00:00Commented May 4, 2016 at 6:58
Based on the solution given by @Silvinus here is a solution if you deal with array inside nested objects (as it is often the case in results from databases queries) :
checkNested = function(obj, props) {
var splited = props.split('.');
var temp = obj;
for(var index in splited) {
var regExp = /\[([^)]+)\]/;
var matches = regExp.exec(splited[index])
if(matches) {
splited[index] = splited[index].replace(matches[0], '');
}
if(matches) {
if(matches && typeof temp[splited[index]][matches[1]] === 'undefined') return false;
temp = temp[splited[index]][matches[1]];
}
else {
if(!matches && typeof temp[splited[index]] === 'undefined') return false;
temp = temp[splited[index]]
}
}
return true
}
obj = {ok: {ao: [{},{ok: { aa: ''}}]}}
console.log(checkNested(obj, 'ok.ao[1].ok.aa')) // ==> true
console.log(checkNested(obj, 'ok.ao[0].ok.aa')) // ==> false
Explore related questions
See similar questions with these tags.