Почему document.querySelectorAll возвращает StaticNodeList, а не действительный массив?

Это прослушивает меня, что я не могу просто сделать document.querySelectorAll(...).map(...) даже в Firefox 3.6, и я все еще не могу найти ответ, таким образом, я думал, что осуществлю кросспостинг по ТАК вопросу из этого блога:

http://blowery.org/2008/08/29/yay-for-queryselectorall-boo-for-staticnodelist/

Кто-либо знает о технической причине, почему Вы не получаете Массив? Или почему StaticNodeList не наследовался Массиву таким способом, которым Вы могли использовать map, concat, и т.д.?

(BTW, если это - всего одна функция, Вы хотите, можно сделать что-то как NodeList.prototype.map = Array.prototype.map;... но снова, почему эта функциональность (намеренно?) заблокированный во-первых?)

89
задан Crescent Fresh 8 April 2010 в 15:27
поделиться

3 ответа

Я считаю, что это философское решение W3C. Дизайн W3C DOM [spec] довольно ортогонален дизайну JavaScript, поскольку DOM означает нейтральную платформу и язык.

Решения типа « getElementsByFoo () возвращает упорядоченный NodeList » или « querySelectorAll () возвращает StaticNodeList » очень много преднамеренно, так что реализациям не нужно беспокоиться о выравнивании своей возвращаемой структуры данных на основе зависимых от языка реализаций (например, .map доступен для массивов в JavaScript и Ruby, но не в списках на C #).

W3C стремятся к низкому уровню: они скажут, что NodeList должен содержать свойство только для чтения .length типа unsigned long , потому что они считают, что каждая реализация может минимум поддерживают , что , но они не будут явно говорить, что оператор индекса [] должен быть перегружен для поддержки получения позиционных элементов, потому что они не хотят заглушать какой-нибудь бедный маленький язык, который приходит вместе, который хочет для реализации getElementsByFoo () , но не может поддерживать перегрузку оператора.Это преобладающая философия, присутствующая в большей части спецификации.

Джон Ресиг озвучил аналогичный вариант , что и ваш, к которому он добавляет :

Мои аргументы не столько в том, что NodeIterator не очень похож на DOM, он не очень похож на JavaScript. Он не использует возможности языка JavaScript, а использует их в меру своих возможностей ...

Я немного сочувствую. Если бы модель DOM была написана специально с учетом функций JavaScript, она была бы намного менее неудобной и более интуитивно понятной в использовании. В то же время я понимаю дизайнерские решения W3C.

75
ответ дан 24 November 2019 в 07:09
поделиться

Я не знаю, почему он возвращает список узлов вместо массива, возможно, потому что, как и getElementsByTagName, он обновляет результат при обновлении DOM. В любом случае очень простой метод преобразования этого результата в простой массив:

Array.prototype.slice.call(document.querySelectorAll(...));

, а затем вы можете сделать:

Array.prototype.slice.call(document.querySelectorAll(...)).map(...);
42
ответ дан 24 November 2019 в 07:09
поделиться

Просто добавьте к тому, что сказал Полумесяц,

если это всего одна функция, которую вы хотите, вы можете сделать что-нибудь вроде NodeList.prototype.map = Array.prototype.map

Не делайте этого! Это совсем не гарантирует работу.

Ни один из стандартов JavaScript или DOM / BOM не указывает, что функция-конструктор NodeList существует даже как глобальное свойство / window , или что NodeList , возвращенный querySelectorAll унаследует от него, или что его прототип доступен для записи, или что функция Array.prototype.map действительно будет работать с NodeList.

NodeList может быть «объектом-хостом» (и является одним из них в IE и некоторых старых браузерах). Методы Array определены как разрешенные для работы с любым «собственным объектом» JavaScript, который предоставляет числовые свойства и свойства length , но они не обязательны для работы с объектами хоста (и в IE, они этого не делают).

Досадно, что вы не получаете все методы массива в списках DOM (все они, а не только StaticNodeList), но надежного способа обойти это нет. Вам придется вручную преобразовать каждый возвращаемый список DOM в массив:

Array.fromList= function(list) {
    var array= new Array(list.length);
    for (var i= 0, n= list.length; i<n; i++)
        array[i]= list[i];
    return array;
};

Array.fromList(element.childNodes).forEach(function() {
    ...
});
12
ответ дан 24 November 2019 в 07:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: