2

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;
 }
asked May 4, 2016 at 6:08
3
  • @Pedram, you want to get "report" about existence of each property or just for the most(last) nested one? Commented 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 :) Commented May 4, 2016 at 6:45
  • I am wondering why my question should get a down vote! Commented May 4, 2016 at 7:27

4 Answers 4

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

answered May 4, 2016 at 7:44
3
  • 1
    does not work if value of a key is falsy, or null. console.log(fn({ toto: { tata: false } }, "toto.tata")); // false Commented Jan 22, 2022 at 13:54
  • @MorloMbakop, thank you for the hint. now it should work as expected. please see edit. Commented Jan 22, 2022 at 13:59
  • Looks lovely like ost of your answers, although i don't understand it. Commented Jan 22, 2022 at 14:12
3

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

answered May 4, 2016 at 6:21
4
  • This answer fails on the case fn({a:false}, 'a'). Minor point, but there is no need for the variable temp here. Commented May 4, 2016 at 6:23
  • Also, shouldn't it be temp = temp[splited[index]];? For that reason, the test case fn({a: {b: { c: 1 }}}, 'a.b.c') causes a run-time error "Cannot read property 'c' of undefined". Commented 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]] Commented May 4, 2016 at 6:48
  • @Silvinus Thank you, I have modified your answer (minor mistake) and put the correct function in my update. Commented May 4, 2016 at 6:54
1

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;
}
answered May 4, 2016 at 6:17
1
  • why downvote? downvoter, how about some explanation?! Or, maybe, you're just clicking without arguments ? Commented May 4, 2016 at 6:58
0

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
answered Mar 3, 2018 at 23:02

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.