Czy istnieje łatwy sposób, aby natywnie określić, czy istnieje głęboka nieruchomość w obiekcie w JavaScript? Na przykład muszę uzyskać dostęp do właściwości:

var myVal = appData.foo.bar.setting;

Ale istnieje szansa, że foo, foo.bar, albo foo.bar.setting nie został jeszcze zdefiniowany. W Groovy możemy zrobić coś takiego:

def myVal = appData?.foo?.bar?.setting

Czy jest podobny sposób, aby zrobić to w JavaScript, bez konieczności pisania niestandardowej funkcji lub zagnieżdżonych, jeśli instrukcje? Znalazłem Ta odpowiedź była przydatna, ale była Mam nadzieję, że było bardziej elegancki i mniej zwyczajny sposób.

16
A.J. Brown 3 październik 2011, 19:01

7 odpowiedzi

Najlepsza odpowiedź

Uważam to za bardzo wygodne:

var myVal = (myVal=appData) && (myVal=myVal.foo) && (myVal=myVal.bar) && myVal.settings;

Jeśli istnieje właściwość, zostanie podjęta kolejna część sekwencji.

Gdy wyrażenie przed && ocenia się na false, następna część wyrażenia nie zostanie sprawdzona. Jeśli jeden z myVal.appData.foo.bar.settings nie zostanie zdefiniowany, wartość myVal (undefined (oceni się do false.

16
Rob W 3 październik 2011, 15:03

Przepraszam, to nie jest świetne:

var myVal = appData && appData.foo && appData.foo.bar && appData.foo.bar.setting;

Inna opcja:

try {
    var myVal = appData.foo.bar.setting;
} catch (e) {
    var myVal = undefined;
}

The. Operator nie jest bardzo przeznaczony do dostępu do takich obiektów. Prawdopodobnie za pomocą funkcji byłoby dobrym pomysłem.

5
robert 3 październik 2011, 15:12

Uważam, że inne podejścia nieco ogromne. Jaka byłaby główna wadą następującego podejścia:

// Pass the path as a string, parse it, and try to traverse the chain.
Object.prototype.pathExists = function(path) {
    var members = path.split(".");
    var currentMember = this;

    for (var i = 0; i < members.length; i++) {
        // Here we need to take special care of possible method 
        // calls and arrays, but I am too lazy to write it down.
        if (currentMember.hasOwnProperty(members[i])) {
            currentMember = currentMember[members[i]];   
        } else {
            return false;
        }
    }
    return true;
}

Zasadniczo definiujemy metodę na obiekcie (niekoniecznie), a ta metoda pobiera ścieżkę do zagnieżdżonego obiektu i zwraca potwierdzenie egzystencji, jak appData.pathExists("foo.bar.setting");

EDYTOWAĆ: Sprawdź object[prop] == undefined nie jest semantycznie poprawny, ponieważ zwróci fałszywe, nawet jeśli właściwość jest zdefiniowana, chociaż jego wartość jest undefined; Dlatego używam hasOwnProperty, aby sprawdzić, czy właściwość jest zdefiniowana. Może to być ważne, jeśli trzeba po prostu pobrać wartość.

3
bellpeace 26 październik 2012, 05:42

Jeśli, po:

var myVal = appData.foo && appData.foo.bar && appData.foo.bar.setting;

myVal nie jest undefined, będzie miał wartość appData.foo.bar.setting.

2
Yoshi 3 październik 2011, 15:10

Możesz tego spróbować

var x = {y:{z:{a:'b'}}}
x && x.y && x.y.z && x.y.z.a //returns 'b'

To nie jest tak dobre jak wyrażenie Groovy, ale działa. Ocena zatrzymuje się po napotkaniu pierwszej niezdefiniowanej zmiennej.

1
Narendra Yadala 3 październik 2011, 15:09
var product = ...,
    offering = (product||{}).offering,
    merchant = (offering||{}).merchant,
    merchantName = (merchant||{}).name;
if (merchantName)
   displayMerchantName(merchantName);

http://osteele.com/archives/2007/12/cheap-monads.

1
Alex 22 sierpień 2012, 10:55

Właśnie to ugotowałem, więc może nie działać dokładnie dobrze, obejmowałem również dwa przypadki testowe.

function hasPropertyChain(o, properties) {

    var i = 0,
        currentPropertyChain = o;

    if(!o) {
        return false;
    }

    while(currentPropertyChain = currentPropertyChain[properties[i++]]);

    return i - 1 === properties.length;
}


alert(hasPropertyChain({a:{b:{c:'a'}}}, ['a','b','c'])); // true
alert(hasPropertyChain({a:{b:{c:'a'}}}, ['a','b','c', 'd'])); // false
0
Anthony Sottile 3 październik 2011, 15:14