1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
---
title: NodeList
slug: Web/API/NodeList
tags:
- API
- DOM
- Interface
- NodeList
translation_of: Web/API/NodeList
---
<div>{{APIRef("DOM")}}</div>
<p>Объект <strong>NodeList </strong>— это коллекция узлов, возвращаемая такими методами, как {{domxref("Node.childNodes")}} и {{domxref("document.querySelectorAll")}}.</p>
<div class="note">
<p>Несмотря на то, что <code>NodeList</code> не является массивом ( <code>Array</code> ), его вполне возможно перебрать при помощи метода forEach(). NodeList также можно конвертировать в <code>Array</code> при помощи {{jsxref("Array.from()")}}</p>
<p>Однако некоторые старые браузеры на данный момент все еще не поддерживают <code>NodeList.forEach()</code> или <code>Array.from()</code>. Данные ограничения можно обойти, используя {{jsxref("Array.forEach()", "Array.prototype.forEach()")}} ( больше информации на этой странице ).</p>
</div>
<h2 id="Свойства">Свойства</h2>
<dl>
<dt><code>length</code></dt>
<dd>Количество элементов в NodeList.</dd>
</dl>
<h2 id="Методы">Методы</h2>
<dl>
<dt><code><a href="/en-US/docs/DOM/NodeList.item" title="DOM/NodeList.item">item</a> ( idx )</code></dt>
<dd>Возвращает элемент из списка по его индексу или <code>null</code>, если индекс выходит за границы допустимого диапазона. Может быть использован как альтернатива <code>nodeList[idx]</code>, возвращающему <code>undefined</code> при недопустимом <code>idx.</code></dd>
<dt><code>entries()</code></dt>
<dd>Возвращает {{jsxref("Iteration_protocols","iterator")}}, позволяя перебрать все пары ключ/значение, содержащиеся в объекте.</dd>
<dt><code>forEach()</code></dt>
<dd>Выполняет указанную функцию один раз для каждого элемента <code>NodeList</code></dd>
<dt><font face="consolas, Liberation Mono, courier, monospace"><span style="background-color: rgba(220, 220, 220, 0.5);">keys()</span></font></dt>
<dd>Возвращает {{jsxref("Iteration_protocols","iterator")}}, позволяя перебрать все ключи каждой пары ключ/значение, содержащейся в объекте.</dd>
<dt><code>values()</code></dt>
<dd>Возвращает {{jsxref("Iteration_protocols","iterator")}}, позволяя перебрать все значения каждой пары ключ/значение, содержащейся в объекте.</dd>
<dt> </dt>
</dl>
<h2 id="Описание">Описание</h2>
<h3 id="Динамическая_коллекция">Динамическая коллекция</h3>
<p>В определённых случаях <code>NodeList</code> может являться <em>динамической коллекцией</em>. Это означает, что любые изменения в DOM тут же отражаются на коллекции. Примером подобной коллекции является {{domxref("Node.childNodes")}}:</p>
<pre class="brush: js">var parent = document.getElementById('parent');
var child_nodes = parent.childNodes;
console.log(child_nodes.length); // пусть равно "2"
parent.appendChild(document.createElement('div'));
console.log(child_nodes.length); // выведет "3"
</pre>
<p>В других случаях <code>NodeList</code> является <em>статической коллекцией</em>. Это означает, что любые изменения в DOM не отражаются на его содержании. К примеру, {{domxref("document.querySelectorAll")}} возвращает статический <code>NodeList</code>.</p>
<p>Данное деление необходимо иметь в виду при выборе способа обхода элементов <code>NodeList</code>, а также сохранении длины списка в переменную.</p>
<h3 id="Отличия_NodeList_от_Array">Отличия <code>NodeList</code> от <code>Array</code></h3>
<p><code>NodeList</code> используется подобно массивам, и потому может возникнуть закономерное желание использовать в нём методы, предоставляемые <code>Array.prototype</code>. Однако <code>NodeList</code> не реализует методы, подобные таковым у <code>Array</code>.</p>
<p>В JavaScript существует механизм наследования, основанный на прототипах, применяемый как к встроенным («native») (таким как <code>Array</code>), так и «host»-объектам, предоставляемым средой исполнения (таким как <code>NodeList</code>) . Экземпляры класса <code>Array</code> получают свои методы (к примеру, <code>forEach </code>и <code>map</code>) из следующей цепочки наследования:</p>
<p><code>myArray --> Array.prototype --> Object.prototype --> null</code> (Цепочка прототипов объекта может быть получена рекурсивным вызовом <span style="font-family: consolas,monaco,andale mono,monospace;">Object.getPrototypeOf</span>)</p>
<p><code>forEach</code>, <code>map</code>, ровно как и все остальные свойства принадлежат <code>Array.prototype</code>.</p>
<p>Цепочка же прототипов <code>NodeList</code> выглядит следующим образом:</p>
<p><code>myNodeList --> NodeList.prototype --> Object.prototype --> null</code></p>
<p><code>NodeList.prototype</code> содержит метод <code>item</code>, но никак не остальные методы <code>Array.prototype</code>, поэтому они и не могут быть использованы с <code>NodeLists</code>.</p>
<h4 id="Обходные_пути">Обходные пути</h4>
<p>Один из способов решения данной проблемы — это копирование методов из <code>Array.prototype<font face="Open Sans, sans-serif"> в </font></code><code>NodeList.prototype</code>. Однако необходимо отдавать себе отчёт в том, что <a href="http://perfectionkills.com/whats-wrong-with-extending-the-dom/">расширение объектов DOM опасно, особенно в старых версиях Internet Explorer (6, 7, 8)</a>.</p>
<pre class="brush: js">var arrayMethods = Object.getOwnPropertyNames( Array.prototype );
arrayMethods.forEach( attachArrayMethodsToNodeList );
function attachArrayMethodsToNodeList(methodName)
{
if(methodName !== "length") {
NodeList.prototype[methodName] = Array.prototype[methodName];
}
};
var divs = document.getElementsByTagName( 'div' );
var firstDiv = divs[ 0 ];
firstDiv.childNodes.forEach(function( divChild ){
divChild.parentNode.style.color = '#0F0';
});</pre>
<p>Другой подход — расширение непосредственно объектов DOM:</p>
<pre class="brush: js">var forEach = Array.prototype.forEach;
var divs = document.getElementsByTagName( 'div' );
var firstDiv = divs[ 0 ];
forEach.call(firstDiv.childNodes, function( divChild ){
divChild.parentNode.style.color = '#0F0';
});
</pre>
<div class="note">
<p>Стоит отметить, что передача объектов среды (такого как <code>NodeList</code>) через <code>this</code> native-методу (такому как <code>forEach</code>) гарантированно работает не во всех браузерах и точно не работает в некоторых.</p>
</div>
<h2 id="Пример">Пример</h2>
<p>Элементы в <code>NodeList</code>, можно обработать следующим образом:</p>
<pre class="brush: js">for (var i = 0; i < myNodeList.length; ++i) {
var item = myNodeList[i]; // Вызов myNodeList.item(i) необязателен в JavaScript
}
</pre>
<p>Не следует использовать конструкции <code><a href="/en-US/docs/JavaScript/Reference/Statements/for...in" title="JavaScript/ Reference/Statements/for...in">for...in</a></code> или <code><a href="/en-US/docs/JavaScript/Reference/Statements/for_each...in" title="JavaScript/ Reference/Statements/for each...in">for each...in</a></code> для перечисления элементов списка. Эти способы также перечислят и свойства <code>length</code> и <code>item</code>, что приведёт к логическим ошибкам в случае, если скрипт ожидает только объекты {{domxref("node")}}. Также <code>for..in</code> может перечислять свойства в любом порядке.</p>
<p>Циклы <code><a href="/en-US/docs/JavaScript/Reference/Statements/for...of" title="/en-US/docs/JavaScript/Reference/Statements/for...of">for...of</a></code> корректно перечисляют все объекты внутри <code>NodeList</code> в браузерах, в которых поддерживается <code>for...of </code>(например, Firefox 13 или выше):</p>
<pre class="brush: js">var list = document.querySelectorAll( 'input[type=checkbox]' );
for (var item of list) {
item.checked = true;
}</pre>
<h2 id="Конвертирование_NodeList_в_Array">Конвертирование <code>NodeList</code> в <code>Array</code></h2>
<p>Иногда удобнее работать с содержимым <code>NodeList</code>, используя методы <code>Array</code>. Ниже приведена техника преобразования <code>NodeList</code> к <code>Array</code>:</p>
<pre class="brush: js">var div_list = document.querySelectorAll('div'); // returns NodeList
var div_array = Array.prototype.slice.call(div_list); // преобразует NodeList в Array</pre>
<h2 id="Спецификация">Спецификация</h2>
<ul>
<li><a href="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-536297177" title="http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-536297177">DOM Level 3</a></li>
</ul>
|