Зачем нужен документ.querySelectorAll возвращает StaticNodeList, а не реальный массив?
меня раздражает, что я не могу просто сделать document.querySelectorAll(...).map(...) даже в Firefox 3.6, и я все еще не могу найти ответ, поэтому я подумал, что я бы перекрестно разместил вопрос из этого блога:
http://blowery.org/2008/08/29/yay-for-queryselectorall-boo-for-staticnodelist/
кто-нибудь знает техническую причину, почему вы не получаете массив? Или почему StaticNodeList не наследуется от массива таким образом, чтобы вы могли использовать map,concat, и так далее?
(кстати, если это только одна функция, которую вы хотите, вы можете сделать что-то вроде NodeList.prototype.map = Array.prototype.map;...но опять же, почему эта функциональность (намеренно?) заблокирован в первую очередь?)
6 ответов:
Я верю, что это философское решение консорциума W3C. Дизайн W3C дом [спец] вполне ортогонального проектирования в JavaScript, так как дом является означает быть нейтральным к платформе и языку.
решения вроде "
getElementsByFoo()возвращает упорядоченныйNodeList" или "querySelectorAll()возвращает aStaticNodeList" являются очень преднамеренными, так что реализации не должны беспокоиться о выравнивании их возвращаемой структуры данных на основе языковых реализаций (например.mapдоступно на массивах в JavaScript и Ruby, но не в списках на C#).W3C по низкой цель: они скажут, что это
NodeListдолжен содержать только для чтения.lengthсвойство типа unsigned long потому что они считают, что каждая реализация может по крайней мере поддержать это, но они не будут говорить явно, что[]оператор индекса должен быть перегружен для поддержки получения позиционных элементов, потому что они не хотят загонять некоторые бедный маленький язык, который приходит, что хочет реализоватьgetElementsByFoo()но не поддерживает перегрузку операторов. Это распространенная философия, присутствующая во многих спецификациях.Джон в отставку имеет озвучен аналогичный вариант как твое, к которому он добавил:
мой аргумент не так много, что
NodeIteratorне очень дом-как это что это не очень похоже на JavaScript. Оно не использует преимущества функций присутствует в Язык JavaScript и используйте их в меру своих способностей...Я вообще-то сопереживать. Если бы DOM был написан специально с учетом функций JavaScript, это было бы намного менее неудобно и более интуитивно понятно в использовании. В то же время я понимаю дизайнерские решения W3C.
вы можете использовать ES2015 (ES6) распространение оператор:
[...document.querySelectorAll('div')]преобразует StaticNodeList в массив элементов.
вот пример того, как его использовать.
[...document.querySelectorAll('div')].map(x => console.log(x.innerHTML))<div>Text 1</div> <div>Text 2</div>
Я не знаю, почему он возвращает список узлов вместо массива, может быть, потому что, как getElementsByTagName он будет обновлять результат при обновлении DOM. В любом случае очень простой метод преобразования этого результата в простой массив:
Array.prototype.slice.call(document.querySelectorAll(...));и тогда вы можете сделать:
Array.prototype.slice.call(document.querySelectorAll(...)).map(...);
просто чтобы добавить к тому, что сказал полумесяц,
если это только одна функция, которую вы хотите, вы можете сделать что-то вроде NodeList.прототип.карте = массив.прототип.карта
не делай этого! это не гарантирует работу.
нет JavaScript или DOM/BOM стандарт указывает, что
NodeListконструктор-функция даже существует как глобальный/windowсвойство, или что тоNodeListвозвращеноquerySelectorAllунаследует от него, или что его прототип доступен для записи, или что функцияArray.prototype.mapфактически будет работать над списком узлов.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() { ... });
Я думаю, что вы можете просто сделать следующее
Array.prototype.map.call(document.querySelectorAll(...), function(...){...});Он отлично работает для меня
Это вариант, который я хотел бы добавить к ряду других возможностей, предложенных другими здесь. Он предназначен только для интеллектуального удовольствия и является не рекомендуется.
только на развлечения из этого, вот способ "заставить"
querySelectorAllвстать на колени и поклониться вам:Element.prototype.querySelectorAll = (function(QSA){ return function(){ return [...QSA.call(this, arguments[0])] } })(Element.prototype.querySelectorAll);Теперь он чувствует себя хорошо, чтобы перешагнуть через эту функцию, показывая ему, кто босс. Теперь я не знаю, что лучше, создавая совершенно новый имени
Comments