Прелімінарії
У 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);
const root = {
leftChild: {
leftChild: {
leftChild: null,
rightChild: null,
data: 42
},
rightChild: {
leftChild: null,
rightChild: null,
data: 5
}
},
rightChild: {
leftChild: {
leftChild: null,
rightChild: null,
data: 6
},
rightChild: {
leftChild: null,
rightChild: null,
data: 7
}
}
};
function getLeaf(node) {
if (node.leftChild) {
return getLeaf(node.leftChild);
} else if (node.rightChild) {
return getLeaf(node.rightChild);
} else { // node must be a leaf node
return node;
}
}
console.log(getLeaf(root).data);
Більш загальний спосіб отримати доступ до вкладеної структури даних з невідомими ключами та глибиною - це перевірити тип значення та діяти відповідно.
Ось приклад, який додає всі масиви примітивної структури вкладеної структури даних до масиву (припустимо, що він не містить жодних функцій). Якщо ми стикаємося з об'єктом (або масивом), ми просто викликаємо 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;
}
const data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
function toArray(obj) {
const result = [];
for (const prop in obj) {
const value = obj[prop];
if (typeof value === 'object') {
result.push(toArray(value));
} else {
result.push(value);
}
}
return result;
}
console.log(toArray(data));
Помічники
Оскільки структура складного об'єкта або масиву не обов'язково очевидна, ми можемо перевірити значення на кожному кроці, щоб вирішити, як рухатися далі. 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__
. Останнє є внутрішньою властивістю, що використовується для прототипу ланцюга об'єкта. Хоча ланцюжок і успадкування прототипу не відповідає цій відповіді.