Проверьте, определен ли объект, лучшая практика.
У меня есть следующий ответ JSON от ajax-запроса.
var json = {
"response": {
"freeOfChargeProduct": {
"description": "Product",
"orderQty": 5,
"productName": "XYZ",
"qty": 6,
"details": {
"price": 55.5,
"instock": "true",
"focQuantity": 1
}
},
"orderLineId": 4788,
"totalOrderLinePrice": "741.36",
"totalOrderPrice": "1,314.92",
"totalQty": 17
};
JSON не всегда возвращает свойство "freeOfChargeProduct". Поэтому, если я хочу получить цену "freeOfChargeProduct", я должен сделать следующее:
var getFreeOfChargeProductPrice = function() {
var r = json.response;
if (r && r.freeOfChargeProduct && r.freeOfChargeProduct.details) {
return r.freeOfChargeProduct.details.price;
}
return null;
};
Нет проблем. Но очень раздражает проверять каждое свойство объекта, поэтому я создал функцию, которая проверяет, определено ли свойство в объекте.
var getValue = function (str, context) {
var scope = context || window,
properties = str.split('.'), i;
for(i = 0; i < properties.length; i++) {
if (!scope[properties[i]]) {
return null;
}
scope = scope[properties[i]];
}
return scope;
};
var price = getValue('json.response.freeOfChargeProduct.details.price');
// Price is null if no such object exists.
Теперь на мой вопрос: Является ли это хорошим или плохим способом проверить, существует ли свойство в объекте? Любые лучшие предложения/методы?
EDIT:
Я не хочу использовать & -оператор. Я ленив, и я ищу метод повторного использования, чтобы проверить, определен ли объект (или свойство объекта).
:) Спасибо!
Ответы
Ответ 1
if(x && typeof x.y != 'undefined') {
...
}
// or better
function isDefined(x) {
var undefined;
return x !== undefined;
}
if(x && isDefined(x.y)) {
...
}
Это будет работать для любого типа данных в JavaScript, даже для числа, которое равно нулю. Если вы проверяете объект или строку, просто используйте x && x.y
в инструкции if, или если вы уже знаете, что x является объектом, if(x.y) ...
Ответ 2
Используйте шаблон защиты:
if (json.response && json.response.freeOfChargeProduct && json.response.freeOfChargeProduct.details) {
// you can safely access the price
}
Вот как работает шаблон защиты.
if (a && a.b && a.b.c) { ... } else { ... }
Первая проверка: "Существует ли свойство a
?". Если нет, else-branch выполняется. Если да, то происходит следующая проверка: "Объект a
содержит свойство b
?". Если нет, выполняется else-branch. Если да, то происходит окончательная проверка: "Объект a.b
содержит свойство c
?". Если нет, выполняется else-branch. Если да (и только тогда), выполняется if-ветвь.
Обновление: почему он называется "шаблон защиты"?
var value = a && b;
В этом примере элемент b
(правый операнд) охраняется оператором &&
. Только если член a
(левый операнд) правдивый ( "достойный" ), то возвращается только член b
. Если, однако, член a
является ложным ( "недостоин" ), то он сам возвращается.
BTW, члены являются ложными, если они возвращают эти значения: null
, undefined
, 0
, ""
, false
, NaN
. Члены являются правдивыми во всех других случаях.
Ответ 3
Это не проблема синтаксиса, поскольку это проблема с шаблоном проектирования.
Вопрос А.
* У вас есть контроль над json-сервером?
Если ответ на этот вопрос отрицательный, я предполагаю, что все будет на клиенте.
Прочтите следующее:
http://martinfowler.com/eaaDev/PresentationModel.html
Поскольку сервер является источником, в этом случае он предоставит модель.
Этот шаблон указывает дополнительный артефакт: модель представления (PM). В javascript я бы предложил два артефакта, дополнительный для кода конвертера.
В соответствии с этим шаблоном проектирования PM отвечает за преобразование модели в PM и, при необходимости, обратно. В вашем случае не будет никакого преобразования из PM в M.
Это означает, что объект js имеет метод или конструктор, которые переваривают модель и переводят себя с помощью преобразователя (ниже).
Выполняя это, вы получите PM, похожий на это:
var OrderlinePM = {
"hasFreeOfCharge": false | true,
"freeOfCharge" : {...}
enter code here
this.getFreeOfCharge = function() {...
}
this.fromModel = function (jsonEntry, convertor) { // конвертируем это с конвертером;) в для этого конкретного вида, используемого OrderlinePM // также inwith...
}
"OrderLineId": 0,
"TotalOrderLinePrice": "741,36",
"TotalOrderPrice": "1,314.92",
"TotalQty": 17
};
функция mySpecialFunctionPMConvertor {
this.fromModel = functiono() {...//делать странные вещи с моделью и пула PM с ней.
}
}
Хорошо, я отказываюсь от форматирования кода в этом богатом текстовом редакторе: (
- У вас может быть несколько PM: s для разных задач в зависимости от одного и того же объекта модели.
- Кроме того, это сделает объект-конвертер тестируемым в чем-то, что может быть выполнено автоматически.... err ok maby вручную, но в любом случае.
Таким образом, проблема громоздкого кода отражения действительно не проблема. Но сплоченность - это проблема, особенно в JavaScript.
Ответ 4
Вы можете сделать что-то вроде этого:
try{
var focp = json.response.freeOfChargeProduct
var text = "You get " + focp.qty + " of " +
focp.productName +
" for only $" + (focp.qty-focp.details.focQuantity)*focp.details.price +
", You save $" + focp.details.focQuantity*focp.details.price;
$("order_info").innerText = text;
} catch(e) {
// woops, handle error...
}
Он генерирует такое сообщение из предоставленных данных в вашем вопросе, если поля существуют:
Вы получаете 6 из XYZ всего за $277,5, вы экономите $55.5
Если данные не существуют, вы попадете в блок catch. Вы всегда можете просто попробовать Try, Catch, Forget, если вы не можете найти способ справиться с ошибкой (может быть, сделать новый запрос AJAX для данных?).