JavaScript, elegante manier om eigenschappen van geneste objecten te controleren op null/undefined

een “probleem” dat ik af en toe heb, is dat ik een object heb, b.v. user = {}en tijdens het gebruik van de app wordt dit ingevuld. Laten we ergens zeggen, na een AJAX-oproep of zoiets, doe ik dit:

user.loc = {
    lat: 50,
    long: 9
}

Op een andere plaats wil ik controleren of user.loc.latbestaat.

if (user.loc.lat) {
    // do something
}

Als het niet bestaat, zal dit een fout veroorzaken. Als user.loc.latundefinedis, is user.locnatuurlijk ook undefined.

"Cannot read property 'lat' of null" - Dev Tools error

Dat betekent dat ik het als volgt moet controleren:

if (user.loc) {
    if (user.loc.lat) {
        // do something
    }
}

of

if (user.loc && user.loc.lat) {
    // do something
}

Dit is niet echt mooi en hoe groter mijn objecten zijn, hoe erger het wordt – uiteraard (stel je 10 nestniveaus voor).
Ik vind het vervelend dat if(user.loc.lat)niet alleen falseretourneert als user.locundefinedook.

Wat is de ideale manier om dit soort situaties te controleren?


Antwoord 1, autoriteit 100%

U kunt een hulpprogramma als deze gebruiken:

get = function(obj, key) {
    return key.split(".").reduce(function(o, x) {
        return (typeof o == "undefined" || o === null) ? o : o[x];
    }, obj);
}

Gebruik:

get(user, 'loc.lat')     // 50
 get(user, 'loc.foo.bar') // undefined

Of, om alleen te controleren of een eigenschap bestaat, zonder de waarde ervan te krijgen:

has = function(obj, key) {
    return key.split(".").every(function(x) {
        if(typeof obj != "object" || obj === null || ! x in obj)
            return false;
        obj = obj[x];
        return true;
    });
}
if(has(user, 'loc.lat')) ...

Antwoord 2, autoriteit 16%

U kunt de controles combineren met behulp van luie and:

if(user.loc && user.loc.lat) { ...

Of u gebruikt CoffeeScript. En ES2020 heeft een nieuwe syntaxis ( Nullish coalescing Operator ).

user.loc?.lat?. '...'

die de controles voor loceigendom zou uitvoeren en zou beschermen tegen lege objecten.


Antwoord 3, autoriteit 16%

Nou javascript heeft try-catch. Afhankelijk van wat u werkelijk moet doen (d.w.z. hoe uw else-statement eruit zou zien als het undefinedis), is dat misschien wat u wilt.

voorbeeld:

try {
   user.loc.lat.doSomething();
} catch(error) {
   //report
}

Antwoord 4, autoriteit 4%

Probeer dit if(user && user.loc && user.loc.lat) {...}

U kunt de waarde van null en undefined controleren met typeof

Als .locde waarde falseheeft, dan kun je het proberen

if(user && user.loc && typeof(user.loc)!=="undefined"){...}

Als je een enorm genest object hebt, kijk dan eens naar

Bron.

function checkNested(obj /*, level1, level2, ... levelN*/) {
  var args = Array.prototype.slice.call(arguments),
      obj = args.shift();
  for (var i = 0; i < args.length; i++) {
    if (!obj.hasOwnProperty(args[i])) {
      return false;
    }
    obj = obj[args[i]];
  }
  return true;
}
var test = {level1:{level2:{level3:'level3'}} };
checkNested(test, 'level1', 'level2', 'level3'); // true
checkNested(test, 'level1', 'level2', 'foo'); // false

Bijwerken:
Probeer lodash.get

Other episodes