0

I wonder if there is some way to use hasOwnProperty for an object for multiple levels.

To illustrate: I have following object:

var Client = {
    ID: 1,
    Details: {
        Title: 'Dr',
        Sex: 'male'
    }
}

I can now do the following in javascript:

('Title' in Client.Details) -> true

However I cannot! do:

('Street' in Client.Adress)

...yet I must first use an if to not throw an error. Because I might have a large object - I only need to know if there is "Adress" in Client.Details without using prior if statements, any idea if that is possible?

// this is overkill -> (will be many more if-statements for checking a lower level
if('Adress' in Client){
    console.log('Street' in Client.Adress)
} else {
    console.log(false)
}

Example which produces the error:

var Client = {
    ID: 1,
    Details: {
        Title: 'Dr',
        Sex: 'male'
    }
}

// Results in Error:
('Street' in Client.Adress)

// Results in Error:
if('Street' in Client.Adress){}
DavidDunham
  • 1,245
  • 1
  • 22
  • 44
  • 2
    `console.log('Adress' in Client && 'Street' in Client.Adress)`? – Bergi Sep 13 '18 at 13:48
  • I have added an example for you that shows there is an error – DavidDunham Sep 13 '18 at 14:03
  • Yes I see that there's an error. But no, it's not overkill to check for every property that you are accessing, and no you don't need many more `if` statements for that. – Bergi Sep 13 '18 at 14:13
  • Well above is a very simplified example. Imaging an object with 10+ levels and I merely want to know if at level 7 there is object "XYZ" present or not. That would mean 6 (I think) if-statements just to not have the code crash in an error, which in my opinion is overkill – DavidDunham Sep 13 '18 at 14:41
  • No, not `if` statements! Just chain them together using the `&&` operator. You can put that expression in a *single* `if` condition. For alternative approaches see the duplicates – Bergi Sep 13 '18 at 14:45
  • I have updated the sniped for you, the if also runs into an error – DavidDunham Sep 13 '18 at 14:56
  • That's not the expression I suggested in my first comment – Bergi Sep 13 '18 at 14:57
  • Correct, yet your answer did not help my original problem in the first place. – DavidDunham Sep 14 '18 at 06:27

1 Answers1

4

You could pass the path of your attributes via a String and use a recursive function to run your object down:

const checkPath = (o, path) => {
  if(path.includes('.')){
    if(o.hasOwnProperty(path.split('.')[0])) return checkPath(o[path.split('.')[0]], path.split('.').slice(1).join('.'));
    else return false
  }else return o.hasOwnProperty(path);
}

And use it like this :

checkPath(Client, 'Details.Title')

Demo:

let Client = {
    ID: 1,
    Details: {
        Title: 'Dr',
        Sex: 'male'
    }
};

const checkPath = (o, path) => {
  if(path.includes('.')){
    if(o.hasOwnProperty(path.split('.')[0])) return checkPath(o[path.split('.')[0]], path.split('.').slice(1).join('.'));
    else return false
  }else return o.hasOwnProperty(path);
}

console.log(checkPath(Client, 'Details.Title'));
console.log(checkPath(Client, 'Test.Title'));

Here's the sexy one-liner:

const checkPath = (o, path) => path.includes('.') ? o.hasOwnProperty(path.split('.')[0]) ? checkPath(o[path.split('.')[0]], path.split('.').slice(1).join('.')) : false : o.hasOwnProperty(path);
Zenoo
  • 12,670
  • 4
  • 45
  • 69
  • Seems good. Tried with checkPath(Client, 'Details.Address.Drive') and it works. Do you think there is any problems when the object gets more complicated? (containing functions etc.) – DavidDunham Sep 13 '18 at 14:05
  • @DavidDunham It won't execute functions for you, if that's what you mean. Other than that, it should hold fine. – Zenoo Sep 13 '18 at 14:06
  • No I meant if the object complexity (with functions) might break the functionality of your code because it's not "common" to have functions in an object. – DavidDunham Sep 13 '18 at 14:39
  • As I said, if you check for a path that contains a function, it won't execute it, thus will not continue to check the next attribute. – Zenoo Sep 13 '18 at 14:42