Веб

Почему undefined при доступе к json объект в JavaScript

Разбираем ошибку js undefined при работе с объектами js и json объект. Как правильно обращаться к свойствам javascript объекты, использовать опциональную цепочку ?. и проверять ключи для избежания undefined javascript.

5 ответов 2 просмотра

Получение undefined при извлечении значений из JSON-объекта в JavaScript

Я пытаюсь извлечь два значения из следующего JSON-объекта, но при логировании получаю undefined.

json
{
 "categoryDescription": "NR",
 "bopCategoryCode": "Z",
 "forexBOPCategory": {
 "bopSubcategoryCode": "00",
 "rulingCode": "NA",
 "rulingOrSubcategoryDescription": "PS",
 "straightThroughProcess": "N",
 "categoryFlow": "I",
 "transferType": "I",
 "clientType": "NA",
 "sdaAllowed": "Y",
 "fcaAllowed": "N",
 "otherAllowed": "Y",
 "sdaRequireDocument": "Y",
 "documentCount": 1,
 "requiredDocumentCount": 0,
 "thirdPartyCapture": "N",
 "clientResidentialStatus": "Y",
 "bopPaymentRelation": "Y",
 "forexBOPCategoryDocumentsList": [
 {
 "bopCategoryCode": "ZZ1",
 "rulingCode": "NA",
 "documentDescription": "Document Desc",
 "documentShortDescription": "Document S Desc",
 "bopSubcategoryCode": "00"
 }
 ]
 }
}

Мне нужно получить rulingOrSubcategoryDescription и documentShortDescription.

Мой код:

js
this.formData.documentShortDescription = response.forexBOPCategory[0]?.forexBOPCategoryDocumentsList[0].documentShortDescription;
this.formData.rulingOrSubcategoryDescription = response.forexBOPCategory[0]?.rulingOrSubcategoryDescription;

Почему возвращается undefined и как правильно обратиться к этим полям?

Ваш код возвращает undefined, потому что forexBOPCategory в json объект — это обычный объект js, а не массив. Поэтому обращение через [0] ничего не находит и падает на undefined. Правильно извлекать значения напрямую: response.forexBOPCategory.rulingOrSubcategoryDescription для первого поля и response.forexBOPCategory.forexBOPCategoryDocumentsList[0].documentShortDescription для второго — с опциональной цепочкой ?. для защиты от пустых данных.


Содержание


Почему возникает js undefined при работе с объектами js и json объект

Представьте: вы парсите json объект из API, и вдруг console.log(response.forexBOPCategory[0]) выдает undefined. Звучит знакомо? Дело в фундаментальной разнице между объектами js и массивами. В вашем JSON forexBOPCategory — это объект с именованными свойствами вроде "rulingOrSubcategoryDescription": "PS". Объекты js хранят данные как пары “ключ-значение”, где ключи — строки (или символы).

Когда вы пишете [0], JavaScript ищет числовой индекс 0, как в массиве. Но объект — не массив! Он не имеет упорядоченных числовых ключей по умолчанию. Результат? undefined. Это классическая ловушка для новичков в работе с javascript json.

А вот forexBOPCategoryDocumentsList — уже массив внутри объекта. Там [0] сработает, но только после правильного входа в родительский объект js. По данным learn.javascript.ru/object, несуществующие свойства объектов всегда возвращают undefined без ошибок — в отличие от null или отсутствующих массивов.

Почему это важно? JSON из API часто миксует объекты и массивы. Один неверный доступ — и цепочка ломается. В вашем случае response.forexBOPCategory[0] сразу убивает всё.


Как правильно обращаться к свойствам javascript объекты в json объект

Доступ к свойствам javascript объекты проще, чем кажется. Забудьте про [0] для не-массивов. Используйте точку или квадратные скобки.

Через точку (самый читаемый способ):

js
const rulingDesc = response.forexBOPCategory.rulingOrSubcategoryDescription; // "PS"
const docDesc = response.forexBOPCategory.forexBOPCategoryDocumentsList[0].documentShortDescription; // "Document S Desc"

Через скобки (если ключ динамический или с пробелами):

js
const key = 'rulingOrSubcategoryDescription';
const rulingDesc = response.forexBOPCategory[key]; // Работает!

Объекты js — это ассоциативные массивы “под капотом”. Ключи преобразуются в строки. Как объясняет MDN Web Docs по работе с объектами, массивы — частный случай объектов с числовыми ключами. Ваш forexBOPCategoryDocumentsList — именно массив, так что комбинируйте: объект.дочернийМассив[0].свойство.

Деструктуризация упрощает жизнь:

js
const { 
 rulingOrSubcategoryDescription, 
 forexBOPCategoryDocumentsList 
} = response.forexBOPCategory || {};

const docShortDesc = forexBOPCategoryDocumentsList?.[0]?.documentShortDescription;

Быстро? Эффективно. И никаких undefined из ниоткуда.


Опциональная цепочка ?. для безопасного доступа к вложенный объект js

А если forexBOPCategory отсутствует? Или forexBOPCategoryDocumentsList пустой? Без защиты код рухнет с ошибкой “Cannot read property of undefined”. Врывается опциональная цепочка ?. — фича ES2020.

Ваш исправленный код:

js
this.formData.rulingOrSubcategoryDescription = response.forexBOPCategory?.rulingOrSubcategoryDescription || '';
this.formData.documentShortDescription = response.forexBOPCategory?.forexBOPCategoryDocumentsList?.[0]?.documentShortDescription || '';

?. останавливается на первом null или undefined, возвращая undefined вместо краша. Идеально для реальных API, где данные неидеальны.

Поддержка? Везде кроме древних IE. Полифиллы есть. learn.javascript.ru/array рекомендует это для цепочек: obj?.prop?.nested?.[0]?.value. Коротко и надежно.

Но что если нужно значение по умолчанию? Добавьте || '' или логический ?? для nullish (null/undefined).

Пробовали без ?.? Один пропущенный объект — и консоль в слезах. Теперь вы в безопасности.


Проверка свойств: js проверить ключ в объекте и избежать undefined javascript

Не хотите гадать? Проверяйте наличие ключей перед доступом. Несколько способов для js проверить ключ в объекте.

  1. Оператор in (самый быстрый):
js
if ('rulingOrSubcategoryDescription' in response.forexBOPCategory) {
this.formData.rulingOrSubcategoryDescription = response.forexBOPCategory.rulingOrSubcategoryDescription;
}
  1. hasOwnProperty (игнорирует прототип):
js
if (response.forexBOPCategory.hasOwnProperty('forexBOPCategoryDocumentsList')) {
// Доступ безопасен
}
  1. Простое сравнение:
js
const category = response.forexBOPCategory;
if (category && category.rulingOrSubcategoryDescription !== undefined) {
// OK
}

Обсуждение на Stack Overflow подчеркивает: [0] на объектах/строках всегда undefined. in работает даже для унаследованных свойств.

Для массивов: Array.isArray(list) && list.length > 0.

Эти проверки спасут от 90% ошибок с undefined javascript. А вы знали про Object.keys(obj).includes('key')? Медленнее, но читаемо.


Примеры кода: извлечение значений из json объект javascript

Давайте разберем ваш JSON полностью. Полный рабочий пример:

js
// Предполагаем response — ваш parsed JSON
function extractData(response) {
 const category = response?.forexBOPCategory;
 
 if (!category) {
 console.warn('forexBOPCategory отсутствует');
 return { rulingOrSubcategoryDescription: '', documentShortDescription: '' };
 }
 
 const rulingDesc = category.rulingOrSubcategoryDescription || '';
 const docsList = category.forexBOPCategoryDocumentsList || [];
 const docDesc = docsList[0]?.documentShortDescription || '';
 
 return { rulingOrSubcategoryDescription: rulingDesc, documentShortDescription: docDesc };
}

// Использование
const data = extractData(response);
this.formData.rulingOrSubcategoryDescription = data.rulingOrSubcategoryDescription; // "PS"
this.formData.documentShortDescription = data.documentShortDescription; // "Document S Desc"
console.log(data); // Работает!

Бонус: lodash _.get(response, 'forexBOPCategory.rulingOrSubcategoryDescription') — для супер-цепочек.

Тестируйте в консоли. Вставьте JSON — увидите магию. Эти паттерны работают в React, Vue, Node — везде.


Распространенные ошибки с js свойства объекта и как их исправить

  1. Объект путают с массивом: Как у вас. Фикс: console.log(typeof obj) или Array.isArray(obj).

  2. Глубокий доступ без проверок: response.a.b.c крашится. Фикс: ?. везде.

  3. JSON не распарсен: JSON.parse(responseText). Если строка — undefined.

  4. Ключи case-sensitive: “Ruling” ≠ “ruling”. Лог: console.log(Object.keys(obj)).

  5. Пустые массивы: list[0] — undefined. Фикс: list?.[0].

Из MDN: копирование объектов по ссылке — меняете один, меняется все. Используйте structuredClone или {...obj}.

Еще? Async/await с fetch: await response.json(). Забыли — привет, объект FormData.

Эти ошибки бьют всех. Но теперь вы вооружены.


Источники

  1. Объект — Подробное руководство по объектам js и доступу к свойствам: https://learn.javascript.ru/object
  2. Работа с объектами — Официальная документация MDN по javascript объекты и JSON: https://developer.mozilla.org/ru/docs/Web/JavaScript/Guide/Working_with_objects
  3. Почему [1] возвращает undefined — Обсуждение ошибок доступа в объектах на Stack Overflow: https://ru.stackoverflow.com/questions/739332/Почему-1-выдает-undefined
  4. Массив — Различия массивов и объектов js с примерами: https://learn.javascript.ru/array

Заключение

В итоге, проблема с undefined решается пониманием: forexBOPCategory — объект js, а не массив, так что используйте .property вместо [0]. Добавьте ?. и проверки — и код станет пуленепробиваемым для реальных API. Практикуйтесь на console.log(Object.keys()), и такие ошибки уйдут навсегда. Теперь берите ваш json объект javascript и пишите чистый код!

Илья Кантор / Автор учебника по JavaScript

В json объект forexBOPCategory — это объект, а не массив, поэтому response.forexBOPCategory[0] возвращает js undefined. Обращайтесь напрямую: response.forexBOPCategory.rulingOrSubcategoryDescription и response.forexBOPCategory.forexBOPCategoryDocumentsList[0].documentShortDescription. Для безопасности используйте опциональную цепочку: response.forexBOPCategory?.rulingOrSubcategoryDescription. Объекты js — ассоциативные массивы с ключами-строками; несуществующие js свойства объекта дают undefined javascript без ошибки. Проверяйте наличие: 'key' in obj. Это базовый принцип работы с javascript объекты.

M

forexBOPCategory в json объект — обычный объект, не массив, отсюда js undefined при [0]. Доступ к свойствам javascript объекты: obj.prop или obj['prop']; неопределённые дают undefined javascript. Для documentShortDescription: response.forexBOPCategory.forexBOPCategoryDocumentsList[0].documentShortDescription. JavaScript объекты — набор пар «ключ: значение», копируются по ссылке. Массивы — частный случай объектов js с числовыми индексами. Используйте опциональную цепочку ?. для безопасного доступа к вложенный объект js.

R

При обращении к несуществующему индексу в строке или объекте js (как ""[1]) возвращается js undefined, аналогично выходу за пределы массива. В вашем случае forexBOPCategory[0] не работает, т.к. это не массив, а объект; используйте js свойства объекта напрямую. Проверяйте hasOwnProperty('key') или 'key' in obj для js проверить ключ в объекте. Доступ к свойствам через квадратные скобки для вычисляемых ключей в javascript объекты. Избегайте ошибок типа js cannot read property of undefined с помощью проверок.

Илья Кантор / Автор учебника по JavaScript

Ошибка в том, что forexBOPCategoryобъект, а не массив, поэтому [0] даёт js undefined. Правильно: response.forexBOPCategory.rulingOrSubcategoryDescription и response.forexBOPCategory.forexBOPCategoryDocumentsList[0].documentShortDescription. С опциональной цепочкой: response.forexBOPCategory?.forexBOPCategoryDocumentsList?.[0]?.documentShortDescription. Деструктуризация: const { rulingOrSubcategoryDescription } = response.forexBOPCategory. Массивыобъекты js с числовыми индексами; избегайте for..in для переборов. Это решает проблемы с undefined javascript в json объект javascript.

Авторы
Илья Кантор / Автор учебника по JavaScript
Автор учебника по JavaScript
M
Контрибьюторы документации
R
Разработчик
S
Фронтенд-разработчик
A
Разработчик
A
Разработчик
Проверено модерацией
Модерация
Почему undefined при доступе к json объект в JavaScript