Как пройти по объекту JavaScript и проверить наличие нулей?

Скажем, у меня есть объект JavaScript, например:

var obj = {};
obj.computers = {};
obj.computers.favorite = "Commodore 64";
obj.computers.popular = "Apple";

Теперь я могу легко проверить значение null, например:

if(obj != 'undefined' && obj != null) {
    if(obj.computers != 'undefined' && obj.computers != null)) {
        .....

Как видите, если мне нужно увидеть, установлен ли obj.computers.favorite, я действительно должен вложить туда некоторую условную логику. Некоторые из наших объектов имеют глубину 3, 4, 5 уровней.

Вот что я хотел бы делать:

var fav = obj.computers.favorite || 'Unknown';

Но я понимаю, что мне нужно было бы обернуть это каким-то методом. Что-то типа:

var fav = getValueOrDefault(obj.computers.favorite, 'Unknown');

Предложения приветствуются.

Спасибо

ИЗМЕНИТЬ

Моя проверка на «undefined» на самом деле не то, что я использую. Это просто вышло из головы, когда я задавал вопрос. ржу не могу

Но мне было интересно, могу ли я просто обернуть try / catch и выбросить по умолчанию, если исключение?

function(obj, default) {
    try {
        if(obj != null) {
            return obj;
        } else {
            return default;
        }
    } catch(ex) {
        return default;
    }
}

Также спасибо Shusi за указание на повторяющиеся vars.


person cbmeeks    schedule 01.10.2012    source источник
comment
obj != 'undefined' && obj != null неверно, так как для получения строкового значения 'undefined' вам понадобится typeof. Это обычная ошибка. Но в любом случае это излишне многословно. Просто сделайте obj != null, и он одновременно проверит на undefined.   -  person I Hate Lazy    schedule 02.10.2012
comment
getValueOrDefault(obj.computers.favorite, 'Unknown') вызовет исключение, если obj.computers не определены. Вам нужно будет обернуть его строкой и выполнить инкрементный синтаксический анализ объекта.   -  person saml    schedule 02.10.2012
comment
@saml точно. Этого я пытаюсь избежать. Наши объекты JS иногда заходят очень глубоко. Думаю, я мог бы просто попробовать / поймать и вернуть значение по умолчанию, если исключение?   -  person cbmeeks    schedule 02.10.2012
comment
Дополнительная цепочка - это то, что вам нужно stackoverflow.com/a/60845999/2100372   -  person zoran404    schedule 25.03.2020


Ответы (7)


Вы можете сделать это с помощью функции helper. Если я правильно понимаю вашу проблему, ваши объекты могут иметь произвольные глубокие объекты, и вы хотите получить доступ к этим произвольным вложенным свойствам, не загромождая свой код. Я создал Nested функцию, которая позволяет вам get() произвольные свойства, если они установлены, или значения по умолчанию, если они не установлены.

var Nested = function() {};
// prop is a dot-separated path like "foo.bar.baz"
Nested.prototype.get = function(prop, _default) {
    var current = this;
    $.each(prop.split("."), function(i, e) {
        current = current[e] || undefined;
        if (current == undefined)
            return false;
    });
    return current || _default;
}

Затем вы можете написать такой код

var fav = obj.get("computers.favourite", "Linux");
// this emulates
var fav = obj.computers.favourite || "Linux"; // throws error

Как видите, это не столько набор текста. Конечно, это не похоже на обычный Javascript ... Вот скрипка .

person Raffaele    schedule 01.10.2012
comment
эээ, вам нужно изменить объявление var на var current = this; и в коде current = current[e] || undefined;. скрипка тогда будет работать правильно. - person ; 02.10.2012
comment
вы должны упомянуть, что для вашего ответа требуется jquery. - person DrCord; 09.10.2015

Вы действительно можете написать:

(obj && obj.computers && obj.computers.favorite) || 'Unknown'
person CD..    schedule 01.10.2012
comment
+1, но посмотрите мой ответ на общее решение, которое не загромождает код множеством and и более полезно, если OP использует этот шаблон более одного раза. - person Raffaele; 02.10.2012

Я написал это, чтобы помочь вам разобраться с одним из ваших вопросов: «Мне нужно посмотреть, установлен ли obj.computers.favorite».

Object.prototype.isset = function (/* string */ full_path)
{
    var props = full_path.split('.');
    var self = this; /* note that self is usually the window object */

    for (var ii = 0; ii < props.length; ++ii)
    {
        var prop = props[ii];
        var hasMoreComing = ii < props.length - 1 ? true : false;

        if (self[prop] !== null && typeof self[prop] === 'object' && hasMoreComing)
        {
            self = self[prop];
            continue;   // Move up one level.
        }
        else if (hasMoreComing)
            return false;    // ..because user queries a subproperty of a value type

        return self.hasOwnProperty(prop);
    }
};

Тестовый код:

var test = {};

test.kuk = {};
console.log( test.isset('kuk') );  // Prints true.

test.kuk.fitta = {};
console.log( test.isset('kuk.fitta') ); // Prints true.

test.kuk.fitta = null;
console.log( test.isset('kuk.fitta') ); // Prints true.

test.kuk.fitta = undefined;
console.log( test.isset('kuk.fitta') );  // Prints true

delete test.kuk.fitta;
console.log( test.isset('kuk.fitta') );  // Prints false

test.kuk.fitta = 123;
console.log( test.isset('kuk.fitta.doesnt.exist') );  // Prints false
person Martin Andersson    schedule 01.10.2012
comment
Это не работает, как PHP isset, поскольку он возвращает true для null и undefined. - person DrCord; 09.10.2015

К сожалению, не существует очень простого способа обойти это, но вам не нужно проверять одновременно null и undefined. Поскольку null и undefined оба ложны, вы можете просто сделать:

if (obj && obj.computers) {
  var fav = obj.computers.favorite || 'unknown';
}

На самом деле это не касается вашей жалобы, но она менее болезненна, чем вы думаете.

person saml    schedule 01.10.2012

следующая функция примет строку в качестве параметра и вернет объект, если он существует

 function getValueOrDefault(str , obj, deflt){
    var a = str.split("."); o = obj;
    for(var i =0; i < a.length; i++){
         o = obj[a[i]];
         if(!o){
           return deflt;
         }
    }
      return o;
}

var obj = {};
obj.computers = {};
obj.computers.favorite = "Commodore 64";
obj.computers.popular = "Apple";
getValueOrDefault('computers.favorite', obj, 'Unknown');

Примечание: вы не должны использовать var при присвоении свойств объекту, например. var obj.computers.favorite - это СИНТАКСИЧЕСКАЯ ошибка.

person Anoop    schedule 01.10.2012
comment
Я думаю, вы могли бы поменять местами obj и deflt параметры и изменить o = obj || window. чтобы вы могли написать getValueOrDefault('obj.computers.favorite', 'unknown') - person ; 02.10.2012
comment
Да, ты прав. но это решение было более конкретным для вышеуказанного вопроса. - person Anoop; 02.10.2012

необязательный оператор цепочки появился недавно. способ справиться с этим:

let favorite = obj?.computers?.favorite;

Объединяя это с оператором объединения с нулевым значением, вы можете сделать именно то, что было запрошено изначально:

let favorite = obj?.computers?.favorite ?? 'Unknown';

Обратите внимание, что ни один из этих операторов пока не поддерживается повсеместно.

person John Galambos    schedule 25.03.2020

Вы также можете сделать это с помощью функции JavaScript ES5 reduce:

function get(root, member) {
    return member.split('.').reduce((acc, value) => {
        return (acc && typeof acc[value] !== 'undefined') ? acc[value] : undefined
    }, root);
}

Он создает массив из строки элементов, затем аккумулятор постепенно перемещается внутри объекта по мере уменьшения элементов.

Вы можете использовать это так, даже с массивами:

let obj = {
    computers : {
        favorite : "Commodore 64",
        popular : "Apple",
        list: [
            {
                sn : "TDGE52343FD76",
                price: "9867.99",
                options: {
                    fanless: true
                }
            }
        ]
    }
}

get(obj, 'computers.popular');
// => "Apple"
get(obj, 'computers.list.0.sn');
// => "TDGE52343FD76"
get(obj, 'computers.list.0.options.fanless');
// => true
get(obj, 'computers.list.0.options.runsWithoutEletricity');
// => undefined
get(obj, 'computers.list.0.options.runsWithoutEletricity') || "too bad..." ;
// => "too bad..."

Существует код для безопасного обхода объекта js

person Gabriel Glenn    schedule 28.06.2019