Lặp qua các mã con


83

Tôi đang cố gắng lặp lại các Mã con như thế này:

var children = element.childNodes;
children.forEach(function(item){
    console.log(item);
});

Tuy nhiên, nó xuất ra Uncaught TypeError: undefined is not a functiondo forEachchức năng. Tôi cũng thử dùng childrenthay childNodesnhưng không có gì thay đổi.

Có ai biết chuyện gì đang xảy ra không?

Câu trả lời:


121

Biến childrenlà một NodeListthể hiện và NodeLists không đúng Arrayvà do đó chúng không kế thừa forEachphương thức.

Ngoài ra, một số trình duyệt thực sự hỗ trợ nó nodeList.forEach


ES5

Bạn có thể sử dụng slicetừ Arrayđể chuyển đổi NodeListthành thích hợp Array.

var array = Array.prototype.slice.call(children);

Bạn cũng có thể chỉ cần sử dụng callđể gọi forEachvà chuyển nó NodeListlàm ngữ cảnh.

[].forEach.call(children, function(child) {});


ES6

Bạn có thể sử dụng fromphương pháp này để chuyển đổi của bạn NodeListthành một Array.

var array = Array.from(children);

Hoặc bạn cũng có thể sử dụng cú pháp lây lan... như vậy

let array = [ ...children ];


Một bản hack có thể được sử dụng là NodeList.prototype.forEach = Array.prototype.forEachvà sau đó bạn có thể sử dụng forEachvới bất kỳ NodeListmà không cần phải chuyển đổi chúng mỗi lần.

NodeList.prototype.forEach = Array.prototype.forEach
var children = element.childNodes;
children.forEach(function(item){
    console.log(item);
});

Xem phần Tìm hiểu sâu hơn về NodeLists, Mảng, chuyển đổi NodeLists và hiểu DOM để có lời giải thích tốt và các cách khác để thực hiện.


Làm cách nào để chuyển đổi NodeList thành mảng thuần túy?
user3828771

Cập nhật với ví dụ nhưng đọc vào liên kết tôi đăng nó giải thích tất cả :)
GillesC

2
Ngoài ra, bạn có thể làm điều này:[].forEach.call(element.childNodes, child => console.log(child))
XåpplI'-I0llwlg'I -

2
Thậm chí mát es6 cách: let items = [ ...children ]sẽ biến nó thành một mảng
zackify

2
Có một vấn đề lớn khi áp dụng các phương thức Mảng cho NodeLists: NodeLists chẳng hạn như node.childNodes là danh sách trực tiếp và nếu bạn thao tác DOM trong suốt vòng lặp của mình, NodeList có thể thay đổi, có nghĩa là lệnh gọi lại forEach () của tôi không được gọi mọi phần tử của danh sách - hoặc nhiều phần tử hơn phần tử ban đầu trong danh sách - dẫn đến kết quả không thể đoán trước. Tốt hơn là biến NodeList thành một mảng trước khi lặp lại nó.
stephband

30

Tôi đến rất muộn với bữa tiệc, nhưng kể từ đó element.lastChild.nextSibling === null, những điều sau đây dường như là lựa chọn đơn giản nhất đối với tôi:

for(var child=element.firstChild; child!==null; child=child.nextSibling) {
    console.log(child);
}

1
Tùy chọn đơn giản nhất là sử dụng vòng lặp "for" thông thường. Nhưng lựa chọn của bạn là thú vị.
Kirill Reznikov

Tôi thích điều này nhất, đã lên kế hoạch thực hiện tương tự .. hợp lý và không cần chuyển đổi
Ujjwal Singh

23

Đây là cách bạn có thể làm điều đó với for-invòng lặp.

var children = element.childNodes;

for(child in children){
    console.log(children[child]);
}

14
Bạn quên kiểm tra: if (children.hasOwnProperty (child)) {// code here} hoặc bạn sẽ lặp lại các đạo cụ không mong muốn như "length" và v.v.!
Kirill Reznikov

7
Thậm chí tốt hơn: sử dụng for ... of ..., đó là cú pháp ES6.
Jespertheend

4

Thử với forvòng lặp. Nó cho lỗi forEachvì nó là một tập hợp các nút nodelist.

Hoặc điều này sẽ chuyển đổi danh sách nút thành mảng

function toArray(obj) {
  var array = [];
  for (var i = 0; i < obj.length; i++) { 
    array[i] = obj[i];
  }
return array;
}

Hoặc bạn có thể sử dụng cái này

var array = Array.prototype.slice.call(obj);

4

Không thể cưỡng lại để thêm một phương pháp khác, bằng cách sử dụng childElementCount. Nó trả về số lượng nút phần tử con từ một nút cha nhất định, vì vậy bạn có thể lặp lại nó.

for(var i=0, len = parent.childElementCount ; i < len; ++i){
    ... do something with parent.children[i]
    }


2

Hãy thử [duyệt theo thứ tự ngược lại]:

var childs = document.getElementById('parent').childNodes;
var len = childs.length;
if(len --) do {
    console.log('node: ', childs[len]);
} while(len --);

HOẶC [theo thứ tự duyệt]

var childs = document.getElementById('parent').childNodes;
var len = childs.length, i = -1;
if(++i < len) do {
    console.log('node: ', childs[i]);
} while(++i < len);

Vòng lặp for đơn giản dễ đọc hơn vòng lặp while. Tác giả không yêu cầu đảo ngược / đảo ngược thứ tự.
Kirill Reznikov

2

Đây là một cách chức năng của ES6 để lặp qua a NodeList. Phương pháp này sử dụng Array's forEachnhư vậy:

Array.prototype.forEach.call(element.childNodes, f)

Đâu flà hàm vòng lặp nhận các nút con làm tham số đầu tiên và chỉ mục là tham số thứ hai.

Nếu bạn cần lặp lại NodeLists nhiều lần, bạn có thể tạo một phương thức tiện ích chức năng nhỏ từ điều này:

const forEach = f => x => Array.prototype.forEach.call(x, f);

// For example, to log all child nodes
forEach((item) => { console.log(item); })(element.childNodes)

// The functional forEach is handy as you can easily created curried functions
const logChildren = forEach((childNode) => { console.log(childNode); })
logChildren(elementA.childNodes)
logChildren(elementB.childNodes)

(Bạn có thể thực hiện thủ thuật tương tự cho map()và các hàm Mảng khác.)


0

Nếu bạn làm nhiều việc như vậy thì bạn nên xác định chức năng cho chính mình.

if (typeof NodeList.prototype.forEach == "undefined"){
    NodeList.prototype.forEach = function (cb){
        for (var i=0; i < this.length; i++) {
            var node = this[i];
            cb( node, i );
        }
    };
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.