В JavaScript есть ли более простой способ проверить, существует ли свойство свойства?

Есть ли простой способ изначально определить, существует ли глубокое свойство внутри объекта в JavaScript? Например, мне нужно получить доступ к следующему свойству:

var myVal = appData.foo.bar.setting;

Но есть вероятность, что foo, foo.bar или foo.bar.setting еще не определены. В Groovy мы можем сделать что-то вроде этого:

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

Есть ли аналогичный способ сделать это в JavaScript, без необходимости писать пользовательскую функцию или вложенные операторы if? Я нашел этот ответ, чтобы быть полезным, но надеялся, что был более элегантный и менее обычай.

Ответы

Ответ 1

Я считаю это очень удобным:

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

Если свойство существует, будет предпринята попытка выполнить следующую часть последовательности.

Если выражение перед && оценивается как false, следующая часть выражения не будет проверяться. Если какой-либо из myVal.appData.foo.bar.settings не определен, значение myVal (undefined (будет оцениваться до false.

Ответ 2

Извините, это не здорово:

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

Другая опция:

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

. оператор не предназначен для доступа к таким объектам. Вероятно, использование функции было бы хорошей идеей.

Ответ 3

Я нахожу другие подходы немного огромными. Итак, каков был бы главный недостаток следующего подхода:

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

В принципе, мы определяем метод объекта (не обязательно), и этот метод берет путь к вложенному объекту и возвращает подтверждение существования, например appData.pathExists("foo.bar.setting");

EDIT: Проверить object[prop] == undefined не семантически корректно, так как он вернет false, даже если свойство определено, хотя его значение равно undefined; поэтому я использую hasOwnProperty, чтобы проверить, определено ли свойство. Это может быть не важно, если нужно просто получить значение.

Ответ 4

Если, после:

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

myVal не undefined, он будет удерживать значение appData.foo.bar.setting.

Ответ 5

Вы можете попробовать это

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

Это не так хорошо, как выражение groovy, но оно работает. Оценка прекращается после появления первой переменной undefined.

Ответ 6

var product = ...,
    offering = (product||{}).offering,
    merchant = (offering||{}).merchant,
    merchantName = (merchant||{}).name;
if (merchantName)
   displayMerchantName(merchantName);

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

Ответ 7

Я только что приготовил это, чтобы он не работал точно, я также включил два тестовых примера.

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