Sơ bộ
JavaScript chỉ có một loại dữ liệu có thể chứa nhiều giá trị: Object . Một mảng là một dạng đối tượng đặc biệt.
(Đồng bằng) Các đối tượng có dạng
{key: value, key: value, ...}
Mảng có hình thức
[value, value, ...]
Cả mảng và đối tượng phơi bày một key -> value
cấu trúc. Các khóa trong một mảng phải là số, trong khi bất kỳ chuỗi nào cũng có thể được sử dụng làm khóa trong các đối tượng. Các cặp khóa-giá trị cũng được gọi là "thuộc tính" .
Các thuộc tính có thể được truy cập bằng cách sử dụng ký hiệu chấm
const value = obj.someProperty;
hoặc ký hiệu ngoặc , nếu tên thuộc tính sẽ không phải là tên định danh JavaScript hợp lệ [spec] hoặc tên là giá trị của biến:
// 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];
Vì lý do đó, các phần tử mảng chỉ có thể được truy cập bằng cách sử dụng ký hiệu ngoặc:
const value = arr[5]; // arr.5 would be a syntax error
// property name / index as variable
const x = 5;
const value = arr[x];
Đợi ... còn JSON thì sao?
JSON là một biểu diễn văn bản của dữ liệu, giống như XML, YAML, CSV và các dữ liệu khác. Để làm việc với dữ liệu đó, trước tiên, nó phải được chuyển đổi thành các loại dữ liệu JavaScript, tức là mảng và đối tượng (và cách làm việc với những dữ liệu vừa được giải thích). Làm cách nào để phân tích JSON được giải thích trong câu hỏi Phân tích JSON trong JavaScript? .
Đọc thêm tài liệu
Cách truy cập mảng và đối tượng là kiến thức cơ bản về JavaScript và do đó, nên đọc Hướng dẫn JavaScript MDN , đặc biệt là các phần
Truy cập cấu trúc dữ liệu lồng nhau
Cấu trúc dữ liệu lồng nhau là một mảng hoặc đối tượng tham chiếu đến các mảng hoặc đối tượng khác, tức là các giá trị của nó là mảng hoặc đối tượng. Các cấu trúc như vậy có thể được truy cập bằng cách áp dụng liên tục dấu chấm hoặc dấu ngoặc.
Đây là một ví dụ:
const data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
Giả sử chúng ta muốn truy cập vào name
mục thứ hai.
Đây là cách chúng ta có thể làm từng bước một:
Như chúng ta có thể thấy data
là một đối tượng, do đó chúng ta có thể truy cập các thuộc tính của nó bằng cách sử dụng ký hiệu chấm. Các items
tài sản được truy cập như sau:
data.items
Giá trị là một mảng, để truy cập phần tử thứ hai của nó, chúng ta phải sử dụng ký hiệu ngoặc:
data.items[1]
Giá trị này là một đối tượng và chúng tôi sử dụng ký hiệu chấm một lần nữa để truy cập vào thuộc name
tính. Vì vậy, cuối cùng chúng tôi nhận được:
const item_name = data.items[1].name;
Ngoài ra, chúng tôi có thể đã sử dụng ký hiệu dấu ngoặc cho bất kỳ thuộc tính nào, đặc biệt nếu tên chứa các ký tự sẽ làm cho nó không hợp lệ cho việc sử dụng ký hiệu dấu chấm:
const item_name = data['items'][1]['name'];
Tôi đang cố gắng truy cập vào một tài sản nhưng tôi chỉ nhận undefined
lại?
Hầu hết thời gian khi bạn nhận được undefined
, đối tượng / mảng đơn giản là không có thuộc tính với tên đó.
const foo = {bar: {baz: 42}};
console.log(foo.baz); // undefined
Sử dụng console.log
hoặc console.dir
và kiểm tra cấu trúc của đối tượng / mảng. Thuộc tính bạn đang cố truy cập có thể thực sự được xác định trên một đối tượng / mảng lồng nhau.
console.log(foo.bar.baz); // 42
Điều gì xảy ra nếu tên tài sản là động và tôi không biết chúng trước?
Nếu tên thuộc tính không xác định hoặc chúng tôi muốn truy cập tất cả các thuộc tính của một đối tượng / thành phần của mảng, chúng ta có thể sử dụng vòng lặp for...in
[MDN] cho các đối tượng và vòng lặp for
[MDN] cho các mảng để lặp lại trên tất cả các thuộc tính / thành phần.
Các đối tượng
Để lặp lại tất cả các thuộc tính của data
, chúng ta có thể lặp lại đối tượng như vậy:
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
}
Tùy thuộc vào nơi đối tượng đến từ (và những gì bạn muốn làm), bạn có thể phải kiểm tra trong mỗi lần lặp xem liệu tài sản đó có thực sự là một tài sản của đối tượng hay đó là một tài sản được thừa kế. Bạn có thể làm điều này với Object#hasOwnProperty
[MDN] .
Thay thế cho for...in
bằng hasOwnProperty
, bạn có thể sử dụng Object.keys
[MDN] để lấy một mảng các tên thuộc tính :
Object.keys(data).forEach(function(prop) {
// `prop` is the property name
// `data[prop]` is the property value
});
Mảng
Để lặp lại tất cả các phần tử của data.items
mảng , chúng tôi sử dụng một for
vòng lặp:
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`.
}
Người ta cũng có thể sử dụng for...in
để lặp lại trên các mảng, nhưng có những lý do tại sao điều này nên tránh: Tại sao 'for (var item in list)' với các mảng được coi là thực hành xấu trong JavaScript? .
Với sự hỗ trợ trình duyệt ngày càng tăng của ECMAScript 5, phương thức mảng forEach
[MDN] cũng trở thành một thay thế thú vị:
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)
});
Trong các môi trường hỗ trợ ES2015 (ES6), bạn cũng có thể sử dụng vòng lặp [MDN] , nó không chỉ hoạt động cho các mảng, mà còn cho bất kỳ lần lặp nào :for...of
for (const item of data.items) {
// `item` is the array element, **not** the index
}
Trong mỗi lần lặp, for...of
trực tiếp cung cấp cho chúng ta phần tử tiếp theo của lần lặp, không có "chỉ mục" để truy cập hoặc sử dụng.
Điều gì xảy ra nếu tôi không biết "độ sâu" của cấu trúc dữ liệu?
Ngoài các khóa không xác định, "độ sâu" của cấu trúc dữ liệu (nghĩa là có bao nhiêu đối tượng lồng nhau), có thể cũng không xác định được. Làm thế nào để truy cập các thuộc tính lồng nhau sâu thường phụ thuộc vào cấu trúc dữ liệu chính xác.
Nhưng nếu cấu trúc dữ liệu chứa các mẫu lặp lại, ví dụ: biểu diễn của cây nhị phân, giải pháp thường bao gồm để truy cập đệ quy [Wikipedia] mỗi cấp của cấu trúc dữ liệu.
Dưới đây là một ví dụ để có được nút lá đầu tiên của cây nhị phân:
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);
Một cách chung hơn để truy cập cấu trúc dữ liệu lồng nhau với các khóa và độ sâu không xác định là kiểm tra loại giá trị và hành động tương ứng.
Dưới đây là một ví dụ bổ sung tất cả các giá trị nguyên thủy bên trong cấu trúc dữ liệu lồng nhau vào một mảng (giả sử nó không chứa bất kỳ hàm nào). Nếu chúng ta gặp một đối tượng (hoặc mảng), chúng ta chỉ cần gọi toArray
lại vào giá trị đó (cuộc gọi đệ quy).
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));
Người giúp việc
Do cấu trúc của một đối tượng hoặc mảng phức tạp không nhất thiết phải rõ ràng, chúng ta có thể kiểm tra giá trị ở mỗi bước để quyết định cách di chuyển xa hơn. console.log
[MDN] và console.dir
[MDN] giúp chúng tôi thực hiện việc này. Ví dụ: (đầu ra của bảng điều khiển Chrome):
> console.log(data.items)
[ Object, Object ]
Ở đây chúng ta thấy rằng đó data.items
là một mảng có hai phần tử là cả hai đối tượng. Trong bảng điều khiển Chrome, các đối tượng thậm chí có thể được mở rộng và kiểm tra ngay lập tức.
> console.log(data.items[1])
Object
id: 2
name: "bar"
__proto__: Object
Điều này cho chúng ta biết đó data.items[1]
là một đối tượng và sau khi mở rộng nó, chúng ta thấy rằng nó có ba thuộc tính id
, name
và __proto__
. Cái sau là một thuộc tính nội bộ được sử dụng cho chuỗi nguyên mẫu của đối tượng. Chuỗi nguyên mẫu và kế thừa nằm ngoài phạm vi cho câu trả lời này, mặc dù.