2008-09-05 21 views
8

gì có thể là vấn đề với đảo ngược mảng đối tượng DOM như trong đoạn mã sau:Bộ sưu tập Javascript của các đối tượng DOM - tại sao tôi không thể đảo ngược với Array.reverse()?

var imagesArr = new Array(); 
imagesArr = document.getElementById("myDivHolderId").getElementsByTagName("img"); 
imagesArr.reverse(); 

Trong Firefox 3, khi tôi gọi phương thức reverse() kịch bản dừng thực hiện và hiển thị lỗi sau trong giao diện điều khiển của Thanh công cụ Web Developer:

imagesArr.reverse is not a function 

biến imagesArr có thể được lặp thông qua với một vòng lặp for và các yếu tố như imagesArr[i] thể được truy cập, vì vậy tại sao nó không được coi là một mảng khi gọi phương thức reverse()?

Trả lời

13

Vì tên getElementsByTag thực sự trả về cấu trúc NodeList. Nó có mảng tương tự như các thuộc tính lập chỉ mục cho tiện lợi cú pháp, nhưng nó là không phải là một mảng. Ví dụ, tập hợp các mục thực sự liên tục được cập nhật động - nếu bạn thêm một thẻ img mới trong myDivHolderId, nó sẽ tự động xuất hiện trong imagesArr.

Xem http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-536297177 để biết thêm.

1

Dòng đầu tiên của bạn không liên quan, vì nó không ép buộc gán cho biến, javascript hoạt động theo cách khác. imagesArr, không phải là Type Array(), nó thuộc kiểu trả về của getElementsByTagName ("img"). Trong trường hợp này, một HtmlCollection của nó trong Firefox 3.

Các phương pháp duy nhất trên đối tượng này là các chỉ mục và độ dài. Để làm việc ngược lại, chỉ cần lặp lại ngược.

8

getElementsByTag() trả về danh sách NodeList thay vì một mảng. Bạn có thể chuyển đổi một NodeList thành một mảng nhưng lưu ý rằng mảng sẽ là một đối tượng khác, do đó, đảo ngược nó sẽ không ảnh hưởng đến vị trí các nút DOM.

var listNodes = document.getElementById("myDivHolderId").getElementsByTagName("img"); 
var arrayNodes = Array.slice.call(listNodes, 0); 
arrayNodes.reverse(); 

Để thay đổi vị trí, bạn sẽ phải xóa các nút DOM và thêm tất cả lại vào đúng vị trí.

Array.prototype.slice.call(arrayLike, 0) là một cách tuyệt vời để chuyển đổi mảng thành mảng, nhưng nếu bạn đang sử dụng thư viện JavaScript, nó thực sự có thể cung cấp một cách tốt hơn/nhanh hơn để thực hiện. Ví dụ: jQuery có $.makeArray(arrayLike).

Bạn cũng có thể sử dụng phương pháp trực tiếp trên mảng NodeList:

Array.prototype.reverse.call(listNodes); 
+2

Không, bạn không thể gọi trực tiếp phương thức trên 'NodeList', vì chỉ mục của nó không thể ghi. Nó sẽ ném một lỗi. – Bergi

+1

ES6: 'arrayNodes = Array.from (listNodes)' – cregox

1

getElementsByTag() trả về một NodeList thay vì một mảng. Bạn cần phải chuyển đổi NodeList thành một mảng rồi đảo ngược nó.

var imagesArr = [].slice.call(document.getElementById("myDivHolderId").getElementsByTagName("img"), 0).reverse(); 
2

Tôi biết câu hỏi này là cũ nhưng tôi nghĩ rằng nó cần một chút làm rõ như một số các câu trả lời ở đây là lỗi thời như W3C thay đổi định nghĩa, và hậu quả là giá trị trả về của các phương pháp này getElementsByTagName()getElementsByClassName()

Những phương pháp này tính đến thời điểm viết câu trả lời này trả về một đối tượng - trống hoặc không - thuộc loại HTMLCollectionkhôngNodeList.

Nó giống như sự khác biệt giữa các thuộc tính children mà trả về một đối tượng kiểu HTMLCollection vì nó chỉ bao gồm các yếu tố và loại trừ văn bản hoặc nhận xét các nút, và childNodes mà trả về một đối tượng kiểu NodeList vì nó có thể chứa các loại nút khác như văn bản và nhận xét là tốt.

Lưu ý: Tôi sẽ tiếp tục ở đây và thể hiện sự thiếu hiểu biết của mình về lý do tại sao phương pháp querySelectorAll() trả về NodeList chứ không phải HTMLCollection vì nó hoạt động độc quyền trên các nút phần tử trong tài liệu và không có gì khác.

Có lẽ nó có liên quan đến khả năng phủ sóng của các loại nút khác trong tương lai và họ đã tìm giải pháp chứng minh tương lai hơn, ai biết thực sự? :)

EDIT: Tôi nghĩ rằng tôi có lý do đằng sau quyết định này để chọn một số NodeList và không phải là HTMLCollection cho số querySelectorAll().

Vì chúng đã xây dựng HTMLCollection độc quyền và hoàn toàn trực tiếp và vì phương pháp này không cần chức năng trực tiếp này nên họ đã quyết định triển khai NodeList thay vì phục vụ tốt nhất mục đích kinh tế và hiệu quả.

Các vấn đề liên quan