8

Проверка существования вложенного ключа объекта JavaScript

4

У меня есть ссылка на объект:

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 ответ(ов)

0

Вы можете получить доступ к свойствам объекта на любом уровне вложенности, если обрабатывать имя как строку: '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, в противном случае — значение, связанное с последним сегментом.

0

В вашем примере кода вы пытаетесь получить доступ к свойству 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, вы получите сообщение "Значение не определено" вместо ошибки.

0

Этот вопрос устарел. Сегодня вы можете использовать цепочку необязательных свойств (Optional chaining):

let value = test?.level1?.level2?.level3;

Дополнительную информацию можно найти в документации:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

0

Вы можете использовать рекурсивный подход, как показано в вашем примере, чтобы проверить, содержит ли объект необходимые ключи. Вот перевод вашего кода и объяснения на русский язык, в стиле ответа на 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'.

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

0

Я думаю, следующий скрипт предоставляет более читаемое представление.

Сначала определим функцию:

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"))
Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь