Проверка существования вложенного ключа объекта JavaScript
У меня есть ссылка на объект:
var test = {};
который потенциально (но не сразу) может содержать вложенные объекты, например:
{level1: {level2: {level3: "level3"}}};
Какой самый хороший способ проверить наличие свойства в глубоко вложенных объектах?
Вызов alert(test.level1);
возвращает undefined
, но alert(test.level1.level2.level3);
вызывает ошибку.
В настоящий момент я делаю так:
if(test.level1 && test.level1.level2 && test.level1.level2.level3) {
alert(test.level1.level2.level3);
}
Но мне интересно, существует ли лучший способ.
5 ответ(ов)
Вы можете получить доступ к свойствам объекта на любом уровне вложенности, если обрабатывать имя как строку: 't.level1.level2.level3'
.
Вот пример кода:
window.t = { level1: { level2: { level3: 'level3' } } };
function deeptest(s) {
s = s.split('.');
var obj = window[s.shift()];
while (obj && s.length) obj = obj[s.shift()];
return obj;
}
alert(deeptest('t.level1.level2.level3') || 'Undefined');
Функция deeptest
разбивает строку на сегменты, используя точку в качестве разделителя. Затем она последовательно проверяет каждый уровень вложенности объекта. Если какой-либо из сегментов является undefined
, функция вернет undefined
, в противном случае — значение, связанное с последним сегментом.
В вашем примере кода вы пытаетесь получить доступ к свойству level3
, находящемуся на глубоком уровне вложенности объекта test
. Однако, если test
, test.level1
, или test.level1.level2
не определены, это приведет к ошибке TypeError
. Чтобы избежать этой ошибки, вы можете использовать оператор опционального связывания (?.
), который позволит безопасно обратиться к вложенным свойствам. Вот как это можно сделать:
try {
alert(test.level1?.level2?.level3);
} catch(e) {
// Обработка исключений
console.error(e);
}
В этом коде, если level1
или level2
не существует, код не выбросит ошибку, а просто вернёт undefined
, что предотвратит возникновение исключения. Если вам нужно, чтобы в случае отсутствия значения отображалось что-то другое, вы можете использовать оператор нулевого слияния (??
):
try {
alert(test.level1?.level2?.level3 ?? 'Значение не определено');
} catch(e) {
// Обработка исключений
console.error(e);
}
Таким образом, если level3
будет undefined
, вы получите сообщение "Значение не определено" вместо ошибки.
Этот вопрос устарел. Сегодня вы можете использовать цепочку необязательных свойств (Optional chaining):
let value = test?.level1?.level2?.level3;
Дополнительную информацию можно найти в документации:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
Вы можете использовать рекурсивный подход, как показано в вашем примере, чтобы проверить, содержит ли объект необходимые ключи. Вот перевод вашего кода и объяснения на русский язык, в стиле ответа на StackOverflow:
function objHasKeys(obj, keys) {
var next = keys.shift();
return obj[next] && (!keys.length || objHasKeys(obj[next], keys));
}
В данном коде условие !keys.length ||
позволяет выйти из рекурсии, когда больше нет ключей для проверки. Это предотвращает вызов функции с пустым массивом ключей.
Пример тестов:
let obj = {
path: {
to: {
the: {
goodKey: "hello"
}
}
}
}
console.log(objHasKeys(obj, ['path', 'to', 'the', 'goodKey'])); // true
console.log(objHasKeys(obj, ['path', 'to', 'the', 'badKey'])); // undefined
В первом примере функция возвращает true
, так как все ключи существуют, а во втором — undefined
, поскольку badKey
отсутствует в объекте.
Вы можете использовать эту функцию для отображения данных из объектов с неизвестными ключами/значениями. Например:
var biosName = objHasKeys(myObj, 'MachineInfo:BiosInfo:Name'.split(':'))
? myObj.MachineInfo.BiosInfo.Name
: 'unknown';
Здесь вы проверяете наличие ключей, разделенных двоеточиями, и если они существуют, то выводите соответствующее значение. В противном случае отображается строка 'unknown'.
Если у вас есть дополнительные вопросы или вам нужна помощь с доработкой функции, не стесняйтесь задавать!
Я думаю, следующий скрипт предоставляет более читаемое представление.
Сначала определим функцию:
var o = function(obj) { return obj || {}; };
Затем используем её вот так:
if (o(o(o(o(test).level1).level2).level3)) {
}
Я называю это «техникой грустного клоуна», потому что используется знак o
.
EDIT:
Вот версия для TypeScript.
Она предоставляет проверку типов на этапе компиляции (а также подсказки, если вы используете инструменты, например, Visual Studio):
export function o<T>(someObject: T, defaultValue: T = {} as T): T {
if (typeof someObject === 'undefined' || someObject === null)
return defaultValue;
else
return someObject;
}
Использование остаётся тем же:
o(o(o(o(test).level1).level2).level3)
Но на этот раз подсказки работают!
Кроме того, вы можете установить значение по умолчанию:
o(o(o(o(o(test).level1).level2).level3, "none"))
Как удалить свойство из объекта JavaScript?
Как получить доступ к вложенным объектам, массивам или JSON и обработать их?
Доступ к свойству объекта с динамически вычисляемым именем
Сортировка свойств объекта по значениям
Почему null является объектом и в чем разница между null и undefined?