Як я можу отримати доступ та обробити вкладені об'єкти, масиви чи JSON?


874

У мене є вкладена структура даних, що містить об'єкти та масиви. Як я можу отримати інформацію, тобто отримати доступ до певного або декількох значень (або ключів)?

Наприклад:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

Як я міг отримати доступ nameдо другого пункту items?


22
@Marcel: Його слід читати як "У мене є структура вкладених даних або JSON. Як я можу отримати доступ до певного значення?". Я знаю різницю, але багато людей не і можуть шукати "JSON", а не "об'єкт". Багато питань насправді мають форму "як я можу отримати доступ до X у цій JSON". Єдине місце, де я згадую JSON у своїй відповіді, там, де я пояснюю, що це таке. Якщо у вас є пропозиція, як краще це донести, я все чую.
Фелікс Клінг

можливий дублікат JSON знайти у JavaScript
Travis J

Відповіді:


1159

Прелімінарії

У JavaScript є лише один тип даних, який може містити кілька значень: Об'єкт . Масив являє собою особливу форму об'єкта.

(Звичайна) Об'єкти мають форму

{key: value, key: value, ...}

Масиви мають форму

[value, value, ...]

І масиви, і об'єкти відкривають key -> valueструктуру. Ключі в масиві повинні бути числовими, тоді як будь-який рядок може використовуватися як ключ в об'єктах. Пари ключ-значення також називаються "властивостями" .

Доступ до властивостей можна отримати, використовуючи позначення крапок

const value = obj.someProperty;

або позначення дужки , якщо ім'я властивості не було б дійсним ідентифікатором JavaScript [spec] , або ім'я є значенням змінної:

// the space is not a valid character in identifier names
const value = obj["some Property"];

// property name as variable
const name = "some Property";
const value = obj[name];

З цієї причини до елементів масиву можна отримати доступ лише за допомогою позначення дужок:

const value = arr[5]; // arr.5 would be a syntax error

// property name / index as variable
const x = 5;
const value = arr[x];

Зачекайте ... що з JSON?

JSON - це текстове подання даних, подібно до XML, YAML, CSV та інших. Для роботи з такими даними спочатку потрібно перетворити на типи даних JavaScript, тобто масиви та об’єкти (а як працювати з ними, було лише пояснено). Як проаналізувати JSON пояснюється у питанні Розбір JSON у JavaScript? .

Подальше читання матеріалу

Як отримати доступ до масивів та об'єктів - це фундаментальне знання JavaScript, тому бажано ознайомитися з посібником з JavaScript для MDN , особливо розділами



Доступ до вкладених структур даних

Вкладена структура даних - це масив або об'єкт, який посилається на інші масиви або об'єкти, тобто його значення - це масиви або об'єкти. До таких структур можна дістатись послідовно застосовуючи позначення крапки або дужки.

Ось приклад:

const data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

Припустимо, ми хочемо отримати доступ nameдо другого пункту.

Ось як ми можемо це зробити покроково:

Як ми можемо бачити data, що це об'єкт, отже, ми можемо отримати доступ до його властивостей за допомогою крапкових позначень. Доступ до itemsвласності здійснюється наступним чином:

data.items

Значення - це масив, для доступу до його другого елемента ми повинні використовувати позначення дужок:

data.items[1]

Це значення є об’єктом, і ми знову використовуємо позначення крапки для доступу до nameресурсу. Тож ми зрештою отримуємо:

const item_name = data.items[1].name;

Крім того, ми могли б використовувати позначення дужок для будь-якого з властивостей, особливо якщо ім'я містило символи, які зробили б його недійсним для використання нотації крапок:

const item_name = data['items'][1]['name'];

Я намагаюся отримати доступ до власності, але я undefinedповертаюся лише назад?

Більшу частину часу, коли ви отримуєте undefined, об’єкт / масив просто не має властивості з цим іменем.

const foo = {bar: {baz: 42}};
console.log(foo.baz); // undefined

Використовувати console.logабо console.dirперевіряти структуру об'єкта / масиву. Властивість, до якої ви намагаєтеся отримати доступ, може бути фактично визначена вкладеним об'єктом / масивом.

console.log(foo.bar.baz); // 42

Що робити, якщо назви властивостей динамічні, і я їх не знаю заздалегідь?

Якщо назви властивостей невідомі або ми хочемо отримати доступ до всіх властивостей об’єкта / елементів масиву, ми можемо використовувати цикл for...in [MDN] для об’єктів та цикл for [MDN] для масивів для перегляду всіх властивостей / елементів.

Об'єкти

Щоб повторити всі властивості data, ми можемо повторити об'єкт так:

for (const prop in data) {
    // `prop` contains the name of each property, i.e. `'code'` or `'items'`
    // consequently, `data[prop]` refers to the value of each property, i.e.
    // either `42` or the array
}

Залежно від того, звідки походить об'єкт (і що ви хочете зробити), вам, можливо, доведеться перевірити в кожній ітерації, чи властивість насправді є власністю об'єкта, чи це спадкова властивість. Це можна зробити за допомогою Object#hasOwnProperty [MDN] .

Як альтернатива for...inз hasOwnProperty, ви можете використовувати Object.keys [MDN] , щоб отримати масив імен властивостей :

Object.keys(data).forEach(function(prop) {
  // `prop` is the property name
  // `data[prop]` is the property value
});

Масиви

Для повторення всіх елементів data.items масиву ми використовуємо forцикл:

for(let i = 0, l = data.items.length; i < l; i++) {
    // `i` will take on the values `0`, `1`, `2`,..., i.e. in each iteration
    // we can access the next element in the array with `data.items[i]`, example:
    // 
    // var obj = data.items[i];
    // 
    // Since each element is an object (in our example),
    // we can now access the objects properties with `obj.id` and `obj.name`. 
    // We could also use `data.items[i].id`.
}

Можна також використовувати for...inдля ітерації масивів, але є причини, чому цього слід уникати: Чому "для (var елемент у списку)" з масивами вважається поганою практикою в JavaScript? .

Зі зростаючою підтримкою браузера ECMAScript 5 метод масиву forEach [MDN] також стає цікавою альтернативою:

data.items.forEach(function(value, index, array) {
    // The callback is executed for each element in the array.
    // `value` is the element itself (equivalent to `array[index]`)
    // `index` will be the index of the element in the array
    // `array` is a reference to the array itself (i.e. `data.items` in this case)
}); 

У середовищах, що підтримують ES2015 (ES6), ви також можете використовувати цикл [MDN] , який працює не тільки для масивів, але і для будь-якого ітерабельного :for...of

for (const item of data.items) {
   // `item` is the array element, **not** the index
}

У кожній ітерації, for...ofбезпосередньо дає нам наступний елемент ітерабельності, немає "індексу" для доступу чи використання.


Що робити, якщо "глибина" структури даних мені невідома?

Крім невідомих ключів, "глибина" структури даних (тобто скільки вкладених об'єктів) вона може бути невідома. Як отримати доступ до глибоко вкладених властивостей, зазвичай залежить від точної структури даних.

Але якщо структура даних містить повторювані шаблони, наприклад представлення бінарного дерева, рішення зазвичай включає рекурсивний [Вікіпедія] доступ до кожного рівня структури даних.

Ось приклад отримати перший вузол листя двійкового дерева:

function getLeaf(node) {
    if (node.leftChild) {
        return getLeaf(node.leftChild); // <- recursive call
    }
    else if (node.rightChild) {
        return getLeaf(node.rightChild); // <- recursive call
    }
    else { // node must be a leaf node
        return node;
    }
}

const first_leaf = getLeaf(root);

Більш загальний спосіб отримати доступ до вкладеної структури даних з невідомими ключами та глибиною - це перевірити тип значення та діяти відповідно.

Ось приклад, який додає всі масиви примітивної структури вкладеної структури даних до масиву (припустимо, що він не містить жодних функцій). Якщо ми стикаємося з об'єктом (або масивом), ми просто викликаємо toArrayзнову це значення (рекурсивний виклик).

function toArray(obj) {
    const result = [];
    for (const prop in obj) {
        const value = obj[prop];
        if (typeof value === 'object') {
            result.push(toArray(value)); // <- recursive call
        }
        else {
            result.push(value);
        }
    }
    return result;
}



Помічники

Оскільки структура складного об'єкта або масиву не обов'язково очевидна, ми можемо перевірити значення на кожному кроці, щоб вирішити, як рухатися далі. console.log [MDN] та console.dir [MDN] допомагають нам у цьому. Наприклад (вихід консолі Chrome):

> console.log(data.items)
 [ Object, Object ]

Тут ми бачимо, що data.itemsце масив з двома елементами, які є обома об'єктами. На консолі Chrome об’єкти можна навіть розширити та перевірити негайно.

> console.log(data.items[1])
  Object
     id: 2
     name: "bar"
     __proto__: Object

Це говорить нам, що data.items[1]це об'єкт, і після його розширення ми бачимо, що він має три властивості id, nameі __proto__. Останнє є внутрішньою властивістю, що використовується для прототипу ланцюга об'єкта. Хоча ланцюжок і успадкування прототипу не відповідає цій відповіді.


3
Деякі з того, що тут пов'язано, насправді запитують, як це зробити в jQuery, що, справедливо, спрощує 1 або 2 речі тут. Не впевнений, чи зробити це більше мегапостом або відповісти на них окремо - основні принципи, які тут висвітлюються, що таке об'єкт, що є масивом, як правило, те, що насправді задають ...
Кріс Москіні

1
@ felix-kling Одне з ... з вкладеними об'єктами, такими як let object = {a: 1, b: 2, c: { a: 3, b: 4 }};, це повертає масив, що містить масив для кожного вкладеного об'єкта, чи в цьому випадку [ 1, 2, [ 3, 4 ] ]не було б краще використовувати concat у рекурсивному виклику замість push? (вимагає змінити результат)
ElFitz,

3
Це найглибша відповідь, яку я коли-небудь бачив у програмі Stack Overflow - і вона відповіла на моє запитання! Дякую!
Вільям Джонс

ця одна сторінка змусила мене дізнатися різницю між ARRAY та OBJ
4ni5

76

Ви можете отримати доступ до нього таким чином

data.items[1].name

або

data["items"][1]["name"]

Обидва способи рівні.


Так, але ви не можете зробити дані ["items"]. 1.name
неаумузичний

5
По-перше, це набагато інтуїтивніше, читабельніше та коротше;) Я вважаю за краще використовувати синтаксис властивостей дужок лише тоді, коли ім'я властивості є змінним.
DanteTheSmith

35

У випадку, якщо ви намагаєтеся отримати доступ itemдо структури з прикладу за допомогою, idабо name, не знаючи, що це положення в масиві, найпростішим способом це було б скористатися бібліотекою underscore.js :

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

_.find(data.items, function(item) {
  return item.id === 2;
});
// Object {id: 2, name: "bar"}

З мого досвіду, використання функцій вищого порядку замість forабо for..inциклічності призводить до коду, про який простіше обґрунтувати, а отже, і більш ремонтувати.

Всього мої 2 копійки.


29

Об'єкти та масиви мають багато вбудованих методів, які допоможуть вам обробляти дані.

Примітка. У багатьох прикладах я використовую функції стрілок . Вони подібні до функціональних виразів , але вони пов'язують thisзначення лексично.

Object.keys(), Object.values()(ES 2017) та Object.entries()(ES 2017)

Object.keys()повертає масив ключів об'єкта, Object.values()повертає масив значень об'єкта та Object.entries()повертає масив ключів об'єкта та відповідні значення у форматі [key, value].

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

console.log(Object.keys(obj)) // ['a', 'b', 'c']
console.log(Object.values(obj)) // [1, 2, 3]
console.log(Object.entries(obj)) // [['a', 1], ['b', 2], ['c', 3]]

Object.entries() із завданням for-of циклу та завданням руйнування

const obj = {
  a: 1
 ,b: 2
 ,c: 3
}

for (const [key, value] of Object.entries(obj)) {
  console.log(`key: ${key}, value: ${value}`)
}

Дуже зручно повторювати результат за Object.entries()допомогою завдання for-of-циклу та руйнування .

Цикл for-of дозволяє ітератувати елементи масиву. Синтаксис for (const element of array)(ми можемо замінити constз varабо let, але краще використовувати , constякщо ми не маємо наміру змінювати element).

Призначення деструктуризації дозволяє витягувати значення з масиву чи об'єкта та призначати їх змінним. У цьому випадку const [key, value]означає, що замість того, щоб призначити [key, value]масив element, ми призначимо перший елемент цього масиву keyта другий елемент value. Це рівнозначно цьому:

for (const element of Object.entries(obj)) {
  const key = element[0]
       ,value = element[1]
}

Як бачите, руйнування робить це набагато простіше.

Array.prototype.every() і Array.prototype.some()

У every()метод повертає значення, trueякщо зазначена функція зворотного виклику повертає trueдля кожного елемента масиву. У some()метод повертає значення, trueякщо зазначена функція зворотного виклику повертає trueдля деякого елемента ( по крайней мере , однією).

const arr = [1, 2, 3]

// true, because every element is greater than 0
console.log(arr.every(x => x > 0))
// false, because 3^2 is greater than 5
console.log(arr.every(x => Math.pow(x, 2) < 5))
// true, because 2 is even (the remainder from dividing by 2 is 0)
console.log(arr.some(x => x % 2 === 0))
// false, because none of the elements is equal to 5
console.log(arr.some(x => x === 5))

Array.prototype.find() і Array.prototype.filter()

Ці find()методи повертають перший елемент , який задовольняє умови функції зворотного виклику. filter()Метод повертає масив всіх елементів, що задовольняють умови функції зворотного виклику.

const arr = [1, 2, 3]

// 2, because 2^2 !== 2
console.log(arr.find(x => x !== Math.pow(x, 2)))
// 1, because it's the first element
console.log(arr.find(x => true))
// undefined, because none of the elements equals 7
console.log(arr.find(x => x === 7))

// [2, 3], because these elements are greater than 1
console.log(arr.filter(x => x > 1))
// [1, 2, 3], because the function returns true for all elements
console.log(arr.filter(x => true))
// [], because none of the elements equals neither 6 nor 7
console.log(arr.filter(x => x === 6 || x === 7))

Array.prototype.map()

map()Метод повертає масив з результатами виклику функції зворотного виклику при умови на елементах масиву.

const arr = [1, 2, 3]

console.log(arr.map(x => x + 1)) // [2, 3, 4]
console.log(arr.map(x => String.fromCharCode(96 + x))) // ['a', 'b', 'c']
console.log(arr.map(x => x)) // [1, 2, 3] (no-op)
console.log(arr.map(x => Math.pow(x, 2))) // [1, 4, 9]
console.log(arr.map(String)) // ['1', '2', '3']

Array.prototype.reduce()

reduce()Метод зменшує масив до єдиного значенням, викликавши надану функцію зворотного виклику з двома елементами.

const arr = [1, 2, 3]

// Sum of array elements.
console.log(arr.reduce((a, b) => a + b)) // 6
// The largest number in the array.
console.log(arr.reduce((a, b) => a > b ? a : b)) // 3

reduce()Метод приймає необов'язковий другий параметр, який являє собою первинне значення. Це корисно, коли масив, на який ви телефонуєте, reduce()може мати нуль або один елемент. Наприклад, якщо ми хотіли створити функцію, sum()яка приймає масив як аргумент і повертає суму всіх елементів, ми могли б записати його так:

const sum = arr => arr.reduce((a, b) => a + b, 0)

console.log(sum([]))     // 0
console.log(sum([4]))    // 4
console.log(sum([2, 5])) // 7


Це моя улюблена відповідь. Ви також можете додати приклад для циклу просто доцільних вкладених даних, наприкладObject.keys(data["items"]).forEach(function(key) { console.log(data["items"][key].id); console.log(data["items"][key].name); });
SilverSurfer

25

Часом доступ до вкладеного об'єкта за допомогою рядка може бути бажаним. Простий підхід, наприклад, першого рівня

var obj = { hello: "world" };
var key = "hello";
alert(obj[key]);//world

Але це часто не буває у складного json. Оскільки json стає складнішим, підходи до знаходження значень всередині json також стають складними. Рекурсивний підхід до навігації по json є найкращим, а те, як використовувати цю рекурсію, буде залежати від типу даних, що шукаються. Якщо задіяні умовні заяви, пошук json може бути хорошим інструментом для використання.

Якщо властивість, до якої можна отримати доступ, вже відома, але шлях є складним, наприклад у цьому об’єкті

var obj = {
 arr: [
    { id: 1, name: "larry" },    
    { id: 2, name: "curly" },
    { id: 3, name: "moe" }
 ]
};

І ви знаєте, що хочете отримати перший результат масиву в об'єкті, можливо, ви б хотіли його використовувати

var moe = obj["arr[0].name"];

Однак це спричинить виняток, оскільки немає властивості об'єкта з цим іменем. Вирішити можливість використовувати це було б для вирівнювання дерев яного аспекту. Це можна зробити рекурсивно.

function flatten(obj){
 var root = {};
 (function tree(obj, index){
   var suffix = toString.call(obj) == "[object Array]" ? "]" : "";
   for(var key in obj){
    if(!obj.hasOwnProperty(key))continue;
    root[index+key+suffix] = obj[key];
    if( toString.call(obj[key]) == "[object Array]" )tree(obj[key],index+key+suffix+"[");
    if( toString.call(obj[key]) == "[object Object]" )tree(obj[key],index+key+suffix+".");   
   }
 })(obj,"");
 return root;
}

Тепер складний об’єкт можна згладити

var obj = previous definition;
var flat = flatten(obj);
var moe = flat["arr[0].name"];//moe

Ось jsFiddle Demoтакий підхід використовується.


WTH ви хочете використовувати obj["arr[0].name"]замість obj.arr[0].name? Ви навряд чи потребуєте / хочете мати справу з сплющеними предметами, крім серіалізації.
Бергі

@ Bergi - це питання я бачу зазвичай, і оскільки це використовується канонічно, я опублікував відповідь на цю його версію. Якщо цього уникнути, набагато швидше використовувати obj.arr [0] .name, але іноді люди хочуть передавати рядкові аксесуари навколо, і це є прикладом цього.
Travis J

Урх. Тим не менш, навряд чи є причина згладжувати повний об'єкт лише для використання одного контуру рядка, ви можете просто проаналізувати це і зробити динамічний пошук.
Бергі

14

Це питання досить старе, тому як сучасне оновлення. З настанням ES2015 з'являються альтернативи для отримання необхідних даних. Зараз існує функція, що називається деструктуризацією об'єктів для доступу до вкладених об'єктів.

const data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

const {
  items: [, {
    name: secondName
  }]
} = data;

console.log(secondName);

Наведений вище приклад створює змінну, викликану secondNameз nameключа з масиву, який називається items, самотньо ,каже, що пропустити перший об'єкт у масиві.

Примітно, що для цього прикладу це, мабуть, надмірно, оскільки простий доступ до масиву легше читати, але він корисний при розбитті об'єктів взагалі.

Це дуже короткий вступ до конкретного випадку використання, деструктуризація може бути незвичайним синтаксисом, до якого спочатку звикнути. Я рекомендую ознайомитись з документацією Mozilla про присвоєння руйнування, щоб дізнатися більше.


13

Щоб отримати доступ до вкладеного атрибута, потрібно вказати його ім'я та здійснити пошук через об’єкт.

Якщо ви вже знаєте точний шлях, тоді ви можете жорстко закодувати його у своєму сценарії так:

data['items'][1]['name']

вони також працюють -

data.items[1].name
data['items'][1].name
data.items[1]['name']

Якщо ви не знаєте точного імені раніше, або користувач - це той, хто надає вам ім'я. Потім необхідний динамічний пошук по структурі даних. Деякі з них припустили, що пошук можна здійснити за допомогою forциклу, але існує дуже простий спосіб пройти шлях шляхом використання Array.reduce.

const data = { code: 42, items: [{ id: 1, name: 'foo' }, { id: 2, name: 'bar' }] }
const path = [ 'items', '1', 'name']
let result = path.reduce((a,v) => a[v], data)

Шлях - це спосіб сказати: Спочатку візьміть об’єкт з ключем items, який, мабуть, є масивом. Потім візьміть 1елемент -st (0 індексних масивів). Останнє візьмемо об’єкт з ключем nameу тому елементі масиву, який буває рядок bar.

Якщо у вас дуже довгий шлях, ви можете навіть скористатися, String.splitщоб полегшити все це -

'items.1.name'.split('.').reduce((a,v) => a[v], data)

Це просто звичайний JavaScript, без використання жодних сторонніх бібліотек, таких як jQuery або lodash.


13
var ourStorage = {


"desk":    {
    "drawer": "stapler"
  },
"cabinet": {
    "top drawer": { 
      "folder1": "a file",
      "folder2": "secrets"
    },
    "bottom drawer": "soda"
  }
};
ourStorage.cabinet["top drawer"].folder2; // Outputs -> "secrets"

або

//parent.subParent.subsubParent["almost there"]["final property"]

В основному, використовуйте крапку між кожним нащадком, який розгортається під ним, і коли у вас є назви об'єктів, складені з двох рядків, ви повинні використовувати позначення ["ім'я obj"]. В іншому випадку вистачить лише крапки;

Джерело: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-objects

щоб додати до цього, доступ до вкладених масивів стане так:

var ourPets = [
  {
    animalType: "cat",
    names: [
      "Meowzer",
      "Fluffy",
      "Kit-Cat"
    ]
  },
  {
    animalType: "dog",
    names: [
      "Spot",
      "Bowser",
      "Frankie"
    ]
  }
];
ourPets[0].names[1]; // Outputs "Fluffy"
ourPets[1].names[0]; // Outputs "Spot"

Джерело: https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/basic-javascript/accessing-nested-arrays/

Ще один корисний документ із зображенням вищезгаданої ситуації: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Basics#Bracket_notation

Доступ до власності через крапку в точці: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Property_Accessors#Dot_notation


Хоча це посилання може відповісти на питання, краще включити сюди суттєві частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться. - З огляду
Роберт

1
Я редагував публікацію. Незважаючи на те, що люди швидко поспішали з цим. Наступного разу я утримаюся від надання відповіді.
Джонні

1
@Riddick не утримуйся, просто переконайся, що ти не публікуєш лише посилання
reggaeguitar

12

Ви можете використовувати lodash _getфункцію:

var object = { 'a': [{ 'b': { 'c': 3 } }] };

_.get(object, 'a[0].b.c');
// => 3

9

Використання JSONPath було б одним із найбільш гнучких рішень, якщо ви бажаєте включити бібліотеку: https://github.com/s3u/JSONPath (вузол та браузер)

Для вашого випадку використання шлях json буде таким:

$..items[1].name

тому:

var secondName = jsonPath.eval(data, "$..items[1].name");

1
Використання eval () не є гарним рішенням. Натомість може використовуватися функція першого класу.
pradeep gowda

8

На всякий випадок, хто хто відвідує це питання у 2017 році чи пізніше і шукає простий у запам'ятовуванні спосіб, ось розроблена допис у блозі про доступ до вкладених об’єктів у JavaScript, не бамбуючи

Неможливо прочитати властивість "foo" невизначеної помилки

1. Вкладений шаблон доступу до об'єкта Олівера Стіла

Найпростіший і найпростіший спосіб - використовувати вкладений шаблон доступу до об'єкта Олівера Стіл

const name = ((user || {}).personalInfo || {}).name;

З цим позначенням ви ніколи не зіткнетесь

Не вдається прочитати властивість 'name' для невизначеного .

Ви в основному перевіряєте, чи існує користувач, якщо ні, ви створюєте порожній об'єкт на льоту. Таким чином, до наступного клавіші рівня буде доступний об'єкт, який існує, або порожній об'єкт , але ніколи не буде визначено.

2. Доступ до вкладених об'єктів за допомогою зменшення масиву

Щоб мати доступ до вкладених масивів, ви можете написати власний утиліт зменшення масиву.

const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

// pass in your object structure as array elements
const name = getNestedObject(user, ['personalInfo', 'name']);

// to access nested array, just pass in array index as an element the path array.
const city = getNestedObject(user, ['personalInfo', 'addresses', 0, 'city']);
// this will return the city from the first address item.

Існує також відмінний тип обробки мінімальної типової бібліотеки, яка робить все це за вас.


3
Це питання стосується насамперед властивостей доступу, які існують. Уже виникає питання про те, на що ви посилаєтесь (і вже включаєте більшість своїх рішень): Безпечно отримуйте доступ до вкладених об'єктів Javascript або Доступ до вкладених об’єктів JavaScript за допомогою рядкового ключа . Але все одно: "На жаль, ви не можете отримати доступ до вкладених масивів цим фокусом". Чому ні? Масиви - це об'єкти, тому він повинен працювати так само добре. Чи можете ви навести приклад, коли цього немає?
Фелікс Клінг

1
@FelixKling Коли ми намагаємося отримати доступ до масивів з малюнком Олівера Стіла, ми не зможемо створити масив на 'n' довжину на ходу та отримати доступ до n-го індексу, не отримуючи помилки 'undefined'. Вих. ((user || {}).address || new Array(3))[1].name
Дінеш Пандіян

3
Ви не застосовуєте свій шаблон послідовно. Звичайно, ...[1].barце призведе до помилки, якби елемент 1не існував. Але це також так, ....foo.barякщо fooне існувало. Ви також повинні "охороняти" доступ, 1як і ви "охороняєте" будь-який інший доступ до власності. Масив - просто об’єкт. "Елемент масиву" - просто властивість. Правильно застосовано це було б (((user || {}).address || {})[1] || {}).name.
Фелікс Клінг

1
Це чудово. Мене це не вдарило. Дякую @FelixKling, я піду оновити повідомлення в блозі.
Дінеш Пандіян

2
@DineshPandiyan ви повинні розкрити, що ви автор typy, я щойно прийшов сюди, прочитавши ваш пост у блозі
reggaeguitar

8

Я віддаю перевагу JQuery. Це чистіше і легко читати.

$.each($.parseJSON(data), function (key, value) {
  alert(value.<propertyname>);
});

7

Доступ до динамічно багаторівневого об'єкта.

var obj = {
  name: "john doe",
  subobj: {
    subsubobj: {
      names: "I am sub sub obj"
    }
  }
};

var level = "subobj.subsubobj.names";
level = level.split(".");

var currentObjState = obj;

for (var i = 0; i < level.length; i++) {
  currentObjState = currentObjState[level[i]];
}

console.log(currentObjState);

Робоча скрипка: https://jsfiddle.net/andreitodorut/3mws3kjL/


6

Якщо ви шукаєте один або кілька об’єктів, які відповідають певним критеріям, у вас є кілька варіантів, використовуючи query-js

//will return all elements with an id larger than 1
data.items.where(function(e){return e.id > 1;});
//will return the first element with an id larger than 1
data.items.first(function(e){return e.id > 1;});
//will return the first element with an id larger than 1 
//or the second argument if non are found
data.items.first(function(e){return e.id > 1;},{id:-1,name:""});

Там також є singleі singleOrDefaultвони працюють дуже як firstі firstOrDefaultвідповідно. Різниця лише в тому, що вони будуть кидати, якщо буде знайдено більше одного матчу.

для подальшого пояснення запиту-js ви можете почати з цієї публікації


Я хотів би знати, як це можна покращити. Хочете залишити коментар?
Руна ФС

6

Підкреслення js шляху

Яка бібліотека JavaScript, яка забезпечує цілий безлад корисних functional programmingпомічників без розширення будь-яких вбудованих об'єктів.

Рішення:

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'foo'
  }, {
    id: 2,
    name: 'bar'
  }]
};

var item = _.findWhere(data.items, {
  id: 2
});
if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}

//using find - 

var item = _.find(data.items, function(item) {
  return item.id === 2;
});

if (!_.isUndefined(item)) {
  console.log('NAME =>', item.name);
}

6

Старе питання, але як ніхто не згадував лодаш (лише підкреслення).

Якщо ви вже використовуєте lodash у своєму проекті, я думаю, що це елегантний спосіб зробити це на складному прикладі:

Опція 1

_.get(response, ['output', 'fund', 'data', '0', 'children', '0', 'group', 'myValue'], '')

такий же, як:

Варіант 2

response.output.fund.data[0].children[0].group.myValue

Різниця між першим та другим варіантом полягає в тому, що в Opt 1 якщо у вас є одне з властивостей, відсутнє (невизначене) в шляху, ви не отримуєте помилку, він повертає вам третій параметр.

Для масиву фільтр lodash має, _.find()але я б краще використовувати звичайний filter(). Але я все ж вважаю, що описаний вище метод _.get()є дуже корисним при роботі з дійсно складними даними. У минулому я стикався з дійсно складними API, і це було зручно!

Я сподіваюся, що це може бути корисним для того, хто шукає варіанти для маніпулювання дійсно складними даними, що випливає з назви.


5

Я не думаю, що запитувач стосується лише вкладеного об'єкта одного рівня, тому я представляю наступне демонстраційне повідомлення, щоб продемонструвати, як отримати доступ до вузла глибоко вкладеного об'єкта json. Гаразд, знайдемо вузол з id '5'.

var data = {
  code: 42,
  items: [{
    id: 1,
    name: 'aaa',
    items: [{
        id: 3,
        name: 'ccc'
      }, {
        id: 4,
        name: 'ddd'
      }]
    }, {
    id: 2,
    name: 'bbb',
    items: [{
        id: 5,
        name: 'eee'
      }, {
        id: 6,
        name: 'fff'
      }]
    }]
};

var jsonloop = new JSONLoop(data, 'id', 'items');

jsonloop.findNodeById(data, 5, function(err, node) {
  if (err) {
    document.write(err);
  } else {
    document.write(JSON.stringify(node, null, 2));
  }
});
<script src="https://rawgit.com/dabeng/JSON-Loop/master/JSONLoop.js"></script>


Як отримати доступ до вкладеного об'єкта json за допомогою змінних. data = {a: {b: 'ss'}}; var key = ab дані [ключ] не працює
Pasupathi Rajamanickam

3

Ви можете використовувати синтаксис jsonObject.keyдля доступу до значення. І якщо ви хочете отримати доступ до значення з масиву, тоді ви можете використовувати синтаксис jsonObjectArray[index].key.

Ось приклади коду для доступу до різних значень, щоб дати вам ідею.

        var data = {
            code: 42,
            items: [{
                id: 1,
                name: 'foo'
            }, {
                id: 2,
                name: 'bar'
            }]
        };

        // if you want 'bar'
        console.log(data.items[1].name);

        // if you want array of item names
        console.log(data.items.map(x => x.name));

        // get the id of the item where name = 'bar'
        console.log(data.items.filter(x => (x.name == "bar") ? x.id : null)[0].id);


3

Динамічний підхід

У нижченаведеній deep(data,key)функції ви можете використовувати довільну keyрядок - у вашому випадку items[1].name(ви можете використовувати позначення масиву [i]на будь-якому рівні) - якщо ключ недійсний, то невизначений - це повернення.


2

Пітонічний, рекурсивний та функціональний підхід до розгадування довільних дерев JSON:

handlers = {
    list:  iterate,
    dict:  delve,
    str:   emit_li,
    float: emit_li,
}

def emit_li(stuff, strong=False):
    emission = '<li><strong>%s</strong></li>' if strong else '<li>%s</li>'
    print(emission % stuff)

def iterate(a_list):
    print('<ul>')
    map(unravel, a_list)
    print('</ul>')

def delve(a_dict):
    print('<ul>')
    for key, value in a_dict.items():
        emit_li(key, strong=True)
        unravel(value)
    print('</ul>')

def unravel(structure):
    h = handlers[type(structure)]
    return h(structure)

unravel(data)

де дані - список пітонів (розбирається з текстового рядка JSON):

data = [
    {'data': {'customKey1': 'customValue1',
           'customKey2': {'customSubKey1': {'customSubSubKey1': 'keyvalue'}}},
  'geometry': {'location': {'lat': 37.3860517, 'lng': -122.0838511},
               'viewport': {'northeast': {'lat': 37.4508789,
                                          'lng': -122.0446721},
                            'southwest': {'lat': 37.3567599,
                                          'lng': -122.1178619}}},
  'name': 'Mountain View',
  'scope': 'GOOGLE',
  'types': ['locality', 'political']}
]

6
Це питання стосується JavaScript, а не Python. Не впевнений, чи існує еквівалентне питання для Python.
Фелікс Клінг

2

Функція grep jQuery дозволяє фільтрувати через масив:

var data = {
    code: 42,
    items: [{
        id: 1,
        name: 'foo'
    }, {
        id: 2,
        name: 'bar'
    }]
};

$.grep(data.items, function(item) {
    if (item.id === 2) {
        console.log(item.id); //console id of item
        console.log(item.name); //console name of item
        console.log(item); //console item object
        return item; //returns item object
    }

});
// Object {id: 2, name: "bar"}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


2
// const path = 'info.value[0].item'
// const obj = { info: { value: [ { item: 'it works!' } ], randominfo: 3 }  }
// getValue(path, obj)

export const getValue = ( path , obj) => {
  const newPath = path.replace(/\]/g, "")
  const arrayPath = newPath.split(/[\[\.]+/) || newPath;

  const final = arrayPath.reduce( (obj, k) => obj ?  obj[k] : obj, obj)
  return final;
}

2

У 2020 році ви можете використовувати @ babel / plugin-offer-optional-ланцюжок, дуже легко отримати доступ до вкладених значень в об’єкті.

 const obj = {
 foo: {
   bar: {
     baz: class {
   },
  },
 },
};

const baz = new obj?.foo?.bar?.baz(); // baz instance

const safe = new obj?.qux?.baz(); // undefined
const safe2 = new obj?.foo.bar.qux?.(); // undefined

https://babeljs.io/docs/en/babel-plugin-proposition-optional-chaining

https://github.com/tc39/proposed-optional-chaining


-4

Моє stringdataпоходить з PHP-файлу, але все-таки я вказую тут, в var. Коли я безпосередньо візьму свій json в objнього, нічого не покаже, чому я ставлю свій файл json як

var obj=JSON.parse(stringdata); тому після цього я отримую messageobj і показую у вікні попередження, тоді я отримую, dataщо це json масив, і зберігаю в одній змінній, ArrObjто я читаю перший об'єкт цього масиву з ключовим значенням, як цеArrObj[0].id

     var stringdata={
        "success": true,
        "message": "working",
        "data": [{
                  "id": 1,
                  "name": "foo"
         }]
      };

                var obj=JSON.parse(stringdata);
                var key = "message";
                alert(obj[key]);
                var keyobj = "data";
                var ArrObj =obj[keyobj];

                alert(ArrObj[0].id);

2
Приклад заплутаний, тому що stringjsonце не рядок.
Фелікс Клінг

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.