Để trả lời cho câu hỏi ban đầu, bạn đang sử dụng for/in
không chính xác. Trong mã của bạn, key
là chỉ mục. Vì vậy, để có được giá trị từ mảng giả, bạn phải làm list[key]
và để lấy id, bạn sẽ làm list[key].id
. Nhưng, bạn không nên làm điều này với for/in
ở nơi đầu tiên.
Tóm tắt (được thêm vào tháng 12 năm 2018)
Đừng bao giờ sử dụng for/in
để lặp lại một danh sách nút hoặc HTMLCollection. Những lý do để tránh nó được mô tả dưới đây.
Tất cả các phiên bản gần đây của trình duyệt hiện đại (Safari, Firefox, Chrome, Edge) đều hỗ trợ for/of
lặp trên danh sách DOM như vậy nodeList
hoặc HTMLCollection
.
Đây là một ví dụ:
var list = document.getElementsByClassName("events");
for (let item of list) {
console.log(item.id);
}
Để bao gồm các trình duyệt cũ hơn (bao gồm cả những thứ như IE), điều này sẽ hoạt động ở mọi nơi:
var list= document.getElementsByClassName("events");
for (var i = 0; i < list.length; i++) {
console.log(list[i].id); //second console output
}
Giải thích cho lý do tại sao bạn không nên sử dụng for/in
for/in
có nghĩa là để lặp lại các thuộc tính của một đối tượng. Điều đó có nghĩa là nó sẽ trả về tất cả các thuộc tính lặp lại của một đối tượng. Mặc dù nó có vẻ hoạt động cho một mảng (trả về các phần tử mảng hoặc phần tử giả), nó cũng có thể trả về các thuộc tính khác của đối tượng không phải là những gì bạn đang mong đợi từ các phần tử giống như mảng. Và, đoán xem, một HTMLCollection
hoặc một nodeList
đối tượng có thể có các thuộc tính khác sẽ được trả về bằng một for/in
lần lặp. Tôi vừa thử điều này trong Chrome và lặp lại theo cách bạn đang lặp lại, nó sẽ lấy các mục trong danh sách (chỉ mục 0, 1, 2, v.v ...), nhưng cũng sẽ truy xuất các thuộc tính length
và item
. Các for/in
lặp chỉ đơn giản là sẽ không làm việc cho một HTMLCollection.
Xem http://jsfiddle.net/jfriend00/FzZ2H/ để biết lý do tại sao bạn không thể lặp lại HTMLCollection với for/in
.
Trong Firefox, for/in
phép lặp của bạn sẽ trả về các mục này (tất cả các thuộc tính lặp của đối tượng):
0
1
2
item
namedItem
@@iterator
length
Hy vọng rằng, bây giờ bạn có thể thấy lý do tại sao bạn muốn sử dụng for (var i = 0; i < list.length; i++)
thay vì vậy bạn chỉ có được 0
, 1
và 2
trong lần lặp của bạn.
Sau đây là một sự phát triển về cách các trình duyệt đã phát triển trong khoảng thời gian 2015-2018 cung cấp cho bạn các cách bổ sung để lặp lại. Hiện tại không cần điều này trong các trình duyệt hiện đại vì bạn có thể sử dụng các tùy chọn được mô tả ở trên.
Cập nhật cho ES6 năm 2015
Thêm vào ES6 là Array.from()
nó sẽ chuyển đổi một cấu trúc giống như mảng thành một mảng thực tế. Điều đó cho phép người ta liệt kê một danh sách trực tiếp như thế này:
"use strict";
Array.from(document.getElementsByClassName("events")).forEach(function(item) {
console.log(item.id);
});
Bản demo hoạt động (trong Firefox, Chrome và Edge kể từ tháng 4 năm 2016): https://jsfiddle.net/jfriend00/8ar4xn2s/
Cập nhật cho ES6 năm 2016
Bây giờ bạn có thể sử dụng ES6 cho / của cấu trúc với a NodeList
và an HTMLCollection
bằng cách thêm mã này vào mã của bạn:
NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
HTMLCollection.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
Sau đó, bạn có thể làm:
var list = document.getElementsByClassName("events");
for (var item of list) {
console.log(item.id);
}
Điều này hoạt động trong phiên bản hiện tại của Chrome, Firefox và Edge. Điều này hoạt động vì nó gắn Array iterator vào cả hai nguyên mẫu NodeList và HTMLCollection để khi / cho lặp lại chúng, nó sử dụng iterator Array để lặp lại chúng.
Bản demo hoạt động: http://jsfiddle.net/jfriend00/joy06u4e/ .
Cập nhật lần thứ hai cho ES6 vào tháng 12 năm 2016
Kể từ tháng 12 năm 2016, Symbol.iterator
hỗ trợ đã được tích hợp sẵn cho Chrome v54 và Firefox v50 để mã bên dưới hoạt động. Nó chưa được tích hợp sẵn cho Edge.
var list = document.getElementsByClassName("events");
for (let item of list) {
console.log(item.id);
}
Bản trình diễn hoạt động (trong Chrome và Firefox): http://jsfiddle.net/jfriend00/3ddpz8sp/
Cập nhật lần thứ ba cho ES6 vào tháng 12 năm 2017
Tính đến tháng 12 năm 2017, khả năng này hoạt động trong cạnh 41.16299.15.0 cho một nodeList
như trong document.querySelectorAll()
, nhưng không phải là một HTMLCollection
như trong document.getElementsByClassName()
vì vậy bạn phải tự gán các iterator để sử dụng nó trong Edge cho một HTMLCollection
. Đó là một bí ẩn hoàn toàn tại sao họ sửa một loại bộ sưu tập, nhưng không phải loại khác. Nhưng, ít nhất bạn có thể sử dụng kết quả document.querySelectorAll()
với for/of
cú pháp ES6 trong các phiên bản hiện tại của Edge.
Tôi cũng đã cập nhật jsFiddle ở trên để nó kiểm tra cả hai HTMLCollection
và nodeList
riêng biệt và nắm bắt đầu ra trong chính jsFiddle.
Cập nhật lần thứ tư cho ES6 vào tháng 3 năm 2018
Trên mỗi mesqueeeb, Symbol.iterator
hỗ trợ cũng đã được tích hợp vào Safari, vì vậy bạn có thể sử dụng for (let item of list)
cho một trong hai document.getElementsByClassName()
hoặc document.querySelectorAll()
.
Cập nhật lần thứ năm cho ES6 vào tháng 4 năm 2018
Rõ ràng, hỗ trợ cho việc lặp lại HTMLCollection
với for/of
sẽ đến với Edge 18 vào mùa thu 2018.
Cập nhật lần thứ sáu cho ES6 vào tháng 11 năm 2018
Tôi có thể xác nhận rằng với Microsoft Edge v18 (được bao gồm trong Windows Update mùa thu 2018), giờ đây bạn có thể lặp lại cả HTMLCollection và NodeList với for / of trong Edge.
Vì vậy, bây giờ tất cả các trình duyệt hiện đại đều có hỗ trợ riêng cho việc for/of
lặp lại cả hai đối tượng HTMLCollection và NodeList.