Тестирование вложенных объектов как undefined в Javascript
Возможный дубликат:
javascript test для существования ключа вложенных объектов
Я пытаюсь создать сообщение об ошибке для formset
путем тестирования, если определенный объект не является undefined
, а если он не undefined
, я в конечном итоге заполняю его этим сообщением об ошибке. Основная проблема заключается в том, что я должен проверять, есть ли каждый вложенный объект undefined
, что приводит к некоторому довольно уродливому коду. Вот пример:
errorsForField: function(fieldName, formsetName, formNumber) {
if (typeof this.model.errors != 'undefined'){
var fieldError = document.createElement('span');
$(fieldError).addClass('field-error');
// THE FOLLOWING LINE THROWS ERROR.
if (formsetName && _.isUndefined(this.model.errors[formsetName][fieldName]) != true) {
$(fieldError).text(this.model.errors[formsetname][fieldName]);
} else if (typeof this.model.errors[fieldName] != "undefined"){
$(fieldError).text(this.model.errors[fieldName]);
}
this.errors[fieldName] = fieldError.outerHTML;
return fieldError.outerHTML;
}
return false;
},
Я получаю сообщение об ошибке, что я не могу определить [fieldName]
для undefined object
this.model.errors[formsetName]
. Другими словами, я должен сначала определить, является ли this.model.errors[formsetName]
пустым, а затем проверить, является ли [fieldName]
undefined
.
Это похоже на действительно громоздкое решение. Любые предложения по изменению этого?
Ответы
Ответ 1
Вы можете создать библиотечную функцию, которая принимает имена свойств в качестве параметров и возвращает окончательное значение, если оно существует, или null:
function TryGetPropertyValue(o, propertyName1 /*, ... propertyNameN */) {
var names = [].slice.call(arguments, 1);
while (o && names.length) {
o = o[names.shift()];
}
return names.length ? null : o;
}
Назовите его так:
var err = TryGetPropertyValue(this.model.errors, formsetName, fieldName) ||
TryGetPropertyValue(this.model.errors, fieldName);
if (err != null) {
$(fieldError).text(err);
}
Если вы хотите, чтобы он возвращал undefined
вместо null
, если поле не найдено, вы можете слегка изменить функцию:
function TryGetPropertyValue(o, propertyName1 /*, ... propertyNameN */) {
var names = [].slice.call(arguments, 1);
while (o && names.length) {
o = o[names.shift()];
}
if (names.length == 0) {
return o;
}
}
http://jsfiddle.net/HbggQ/
Ответ 2
Как сказал Павел, это неотъемлемое ограничение Javascript. Даже Coffeescript (который является всего лишь слоем синтаксического сахара поверх JS) на самом деле не решает проблему; он просто скрывает обходной путь под ним синтаксический сахар (который, по общему признанию, очень удобен)
Если вы хотите придерживаться Javascript, у вас в основном есть два варианта: использовать тернарные операторы или использовать логические операторы. Здесь примеры каждого, которые проверяют A.B.C.D(где A, B, C или D могут отсутствовать):
// Returns A.B.C.D, if it exists; otherwise returns false (via ternary)
return !A ? false :
!A.B ? false :
!A.B.C ? false :
A.B.C.D ? A.B.C.D : false;
// Returns A.B.C.D, if it exists; otherwise returns false (via booleans)
return A && A.B && A.B.C && A.B.C.D;
Очевидно, что последнее намного короче. Оба решения полагаются на "правду" Javascript (то есть, что значения 0
, ""
, null
и undefined
считаются ложными). Это должно быть хорошо для вашего случая, так как ни одно из этих значений не будет иметь свойство errors. Однако, если вам нужно различать (скажем) 0
и undefined
, вы можете использовать тройной стиль и заменить !A
на typeof(A) == 'undefined'
.