#javascript
#javascript
Вопрос:
Нужно перехватить любой undefined
во всем пространстве структуры объектного литерала. Проблема в том, что местоположение undefined
не будет предсказуемым:
.object
.result2[0] <--undefined could show its ugly face here, or anywhere above or below!
.thumbnails[0]
.type
.name
.['open']
Это не работает:
if ( typeof object.result2[0].thumbnails[0]..... type == 'undefined'){
console.log("err'd out")
handleError();
}
Итак, я предполагаю, что я ищу решение, которое следует: если что-либо внутри object
не определено, сделайте что-нибудь, или я лаю не на то дерево?
Комментарии:
1. Лично я обычно просто использую try / catch или несколько
if
условий для этого.2. Конечно, что в этом плохого? Try / catch — это легитимный код. Если вы подозреваете, что может быть вызвана другая ошибка, вы всегда можете проверить содержимое ошибки и повторно вызвать или обработать, если это не исключение с нулевой ссылкой. В try / catch нет ничего изначально злого, только некоторые потенциальные накладные расходы на создание информации об исключении.
Ответ №1:
Если вы часто занимаетесь подобными вещами, то небольшая вспомогательная функция полезна:
function dig_out(o, path, def) {
var parts = path.split('.');
for(var i = 0; i < parts.length; i) {
if(typeof o == 'undefined')
return def;
o = o[parts[i]];
}
return o;
}
obj = { a: [1, [2, { b: 10 } ]]};
var x = dig_out(ob, 'a.1.1.b'); // x is now 10
Хитрость в том, чтобы понять, что это:
object.results2[0].thumbnails[0].type.name["open"]
также может быть записан как:
object['results2'][0]['thumbnails'][0]['type']['name']['open']
И это можно легко представить в виде строки:
'results2.0.thumbnails.0.type.name.open'
это легко понять и проанализировать.
Вы также могли бы представить путь в виде массива (как это делает CD Sanchez), но тогда вам пришлось бы что-то делать со значением по умолчанию, def
.
Вы также могли бы разрешить path
аргументу быть массивом:
function dig_out(o, path, def) {
var parts = path instanceof Array ? path : path.split('.');
for(var i = 0; i < parts.length; i) {
if(typeof o == 'undefined')
return def;
o = o[parts[i]];
}
return o;
}
obj = { a: [1, [2, { b: 10 } ]]};
var x = dig_out(obj, 'a.1.1.b'); // x is now 10
var y = dig_out(obj, ['a', 1, 1, 'b']); // y is now 10
Тогда у вас была бы некоторая гибкость в отношении того, с каким форматом аргументов проще всего работать, и это даже не стоило бы так дорого. Спасибо небольшой дискуссии с CD Sanchez за эту идею.
Комментарии:
1. Это потрясающая информация, не специально для этого вопроса, а для моих общих знаний JavaScript. 1.
2. Да, мой был бы более универсальным, если бы его изменили для возврата объекта. Однако в вашем случае я должен прокомментировать, что передача пути в виде строки может быть не лучшим способом сделать это, потому что вы можете в конечном итоге получить уродливые конкатентации строк (или, в лучшем случае, объединение в массив значений), если вы делаете это, например, внутри цикла. например
dig_out(object, 'results2.' i '.thumbnails' ...)
3. @CD: Какой подход вы выбрали, будет зависеть от конкретных обстоятельств. Вы также могли бы проверить, был ли второй аргумент строкой или массивом; если это была строка, то разделите ее, если это был массив, то просто используйте его как есть. У вас не было бы вариативного поведения, но с массивом, вероятно, было бы легче работать в куче вложенных циклов.
4. Хорошо подходит для моей ситуации. Спасибо за помощь!
5. @CD: Я добавил обновление с гибкой обработкой аргументов, я думаю, что это дает нам лучшее из обоих миров.
Ответ №2:
Обычно вы используете
if (object amp;amp; object.result2[0] amp;amp; object.results2[0].thumbnails[0] amp;amp; object.results2[0].thumbnails[0].type amp;amp; object.results2[0].thumbnails[0].type.name) {
object.results2[0].thumbnails[0].type.name["open"]
}
Тот факт, что это выглядит некрасиво, является проблемой с вашей вложенностью и что вещи могут быть неопределенными на каждом уровне.
Комментарии:
1. @cube да, ты знаешь. Это или напишите вспомогательную функцию, как у других ребят.
Ответ №3:
Простой блок try-catch сделает свое дело, без необходимости тестировать каждый уровень.
Комментарии:
1. @cube — Есть ли в вашей компании политика против try / catch в производственном коде? Безусловно, существует потенциал для злоупотреблений, но, кроме довольно противоречивой дискуссии Джоэла Спольски на эту тему и некоторых соображений производительности , которые могут быть / не быть актуальными, я не знаю о каком-либо широком консенсусе о том, что try / catch считается вредным.
2.
try catch
плохо влияет на производительность JavaScript. этого действительно следует избегать, особенно для чего-то такого простого, как это.
Ответ №4:
Если вы действительно хотите сохранить свой код в чистоте, вы могли бы создать простую функцию для проверки, существуют ли все ключи.
function pathExists() { // untested, but the basis is sound
var obj = arguments[0], path = Array.prototype.slice.call(arguments, 1), cursor = obj;
for (var i = 0; i < path.length; i) {
if (typeof cursor[path[i]] == "undefined") return false;
cursor = cursor[path[i]];
}
return cursor;
}
if (!pathExists(object, "result2", 0, "type", "name", "open"))
console.log("bork");