Checking existence of nested property in an object

2020-02-11 10:10发布

问题:

I have already reviewed some of the answers to such question, however, I want to ask my question differently.

Lets 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 that how many nested properties exist in this string. For instance, it may be "level1.level2" or "level1.level2.level3.level4".

Now, I want a function that given the Obj and the string of properties as input, simply tell us that if such a nested property exist in the object or not (lets 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;
    }

回答1:

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



回答2:

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]));
}

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



回答3:

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;
}


回答4:

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