Использование try-catch для получения значения вложенного свойства. Это правильный подход? - PullRequest
2 голосов
/ 19 ноября 2011

У нас есть объект (на который указывает data), и мы хотим получить значение вложенного свойства.В идеале мы хотели бы сделать это так:

value = data.category3.section2.article4.title;

Мы не можем сделать это так, потому что в приведенной выше строке выдается ошибка ссылки, если какой-либо из промежуточных объектов (category3, section2,или article4) не определены (в соответствующих позициях) внутри объекта data.


Теперь, чтобы аннулировать любые потенциальные ссылочные ошибки, которые могут быть выброшены, мы можем просто поместить указанную выше строку внутри оператора try-catch:

try {
    value = data.category3.section2.article4.title;
} catch (err ) {}

Это работает!Однако я не уверен, что полагаться на try-catch подобным образом - хорошая практика.Альтернативным решением было бы вручную перейти к желаемому значению свойства.Я написал компактную служебную функцию, которая выполняет это:

function get( val, names ) {
    names = names.split( '.' );    
    while ( val && names.length ) { val = val[ names.shift() ]; }    
    return val;
}

Теперь мы можем получить значение свойства примерно так:

value = get( data, 'category3.section2.article4.title' );

Итак, мой вопрос:

Является ли подход try-catch верным решением? Или есть веские причины, по которым его следует избегать?

Кстати, подход try-catch сильно смещен в этой теме: Какой самый простой способ проверить существование свойства объекта с глубоким вложением в JavaScript?

Ответы [ 5 ]

2 голосов
/ 22 ноября 2011

Почему бы и нет:

var value = data && 
    data.category3 && 
    data.category3.section2 && 
    data.category3.section2.article4 && 
    data.category3.section2.article4.title;

Это безопасно (если какой-либо из объектов в цепочке обхода не задан, значение будет нулевым). Это немного лучше, чем куча блоков if, и избегает (? Mis) использования исключений.

Другое использование этого метода для предоставления значения по умолчанию при ошибке:

var value = data && 
    data.category3 && 
    data.category3.section2 && 
    data.category3.section2.article4 && 
    data.category3.section2.article4.title || 'default value';
1 голос
/ 21 ноября 2011

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

Например, вторая функция будет возвращать эквивалентные значения undefined для различных обстоятельств, включая data.category3 === undefined и data.category3.section2.article4.title === undefined.Использование try/catch здесь говорит вам, что у вас есть фактическая ошибка обхода, а не свойство, которое не было установлено, которое вы, возможно, захотите обработать по-другому.

1 голос
/ 21 ноября 2011

Оба в порядке. Единственное существенное различие между ними, о котором я могу думать, состоит в том, что

  1. Try-catch может вызвать слишком частую остановку отладчика, если вы скажете ему остановиться во всех исключениях.

    Это уместно, вам нужно отлаживать код, который проглатывает исключения. Например, некоторые библиотеки обещаний помещают все обратные вызовы в блок try-catch.

  2. Версия с разделением строк не может легко справиться со свойствами, которые содержат точку

    var x = {'.': {a: 17}};
    try{ obj['.'].a }catch(e){}
    get(/*???*/)
    

Если вы хотите что-то надежное, чтобы избежать обеих ловушек, я бы предложил функцию, которая может (по крайней мере, опционально) напрямую получать список свойств.

get(val, ['prop1', 0, '.', 'category2']);
0 голосов
/ 04 февраля 2015

Я видел ответы здесь и думаю, что обход - ваш лучший ход, но это выглядит довольно утомительно.Вы можете сделать функцию, которая обходит ее для вас, или вы можете использовать всемогущую библиотеку brototype, найденную по адресу: https://github.com/letsgetrandy/brototype

Таким образом, вы можете сделать что-то вроде этого:

if (Bro(data).doYouEven('category3.section2.article4.title')) {
    value = data.category3.section2.article4.title;
}

или выможно использовать обратный вызов:

Bro(app).iDontAlways('category3.section2.article4.title')
    .butWhenIdo(function(title){
        value = title;
    });

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

Если вам не нравится Brototype, вы действительно можете использовать свой собственныйполучить функцию.

0 голосов
/ 22 ноября 2011

Злоупотребление попытаться поймать, как это грязный хак.

Попробуйте catch, чтобы ловить исключения, которые вы бросаете. Исключения используются для исключительных случаев.

В этом случае оба случая неверны. Вы никогда не должны проходить data.category3.section2.article4.title; там, где каждый шаг может потерпеть неудачу.

Вы просто должны быть в состоянии утверждать, что если data имеет category, то у него должны быть раздел, статья и заголовок.

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

...