javascript arrays internet-explorer foreach microsoft-edge

javascript - forEach on querySelectorAll no funciona en los navegadores recientes de Microsoft



arrays internet-explorer (3)

Bien, comencemos desde aquí, en JavaScript, tenemos algunos casos que lo llamamos tipo Array , lo que significa que incluso parece una matriz, no es una matriz real ...

Por ejemplo, argumentos en función o en su caso Nodelist ...

Incluso todos los navegadores modernos entienden cuál le gustaría cambiar a Array y funcionan bien, en IE y algunos otros navegadores no es compatible con las funciones de matriz en Nodelist, por ejemplo ...

Entonces, si admite una amplia gama de navegadores, es mejor convertirlos a una matriz antes de realizar cualquier actividad en ellos ...

Hay pocas formas de convertir valores similares a Array en Array real ...

Uno ampliamente utilizado en ES5 es esta estructura:

Array.prototype.slice.call (YourNodeList);

Entonces puedes hacer:

var allDivs = document.querySelectorAll("div"); var allRealDivsArray = Array.prototype.slice.call(allDivs);

Pero si usa ES6, hay formas aún más ingeniosas de hacerlo, solo asegúrese de convertirlos a ES5 usando babel, por ejemplo, ya que esos navegadores antiguos que no admiten bucles en forma de matriz, tampoco admitirán ES6 con seguridad. ..

Dos formas muy comunes de hacerlas son:

1) Usando Array.from

const allDivs = document.querySelectorAll("div"); const allRealDivsArray = Array.from(allDivs);

2) Utilizando [... Array]

const allDivs = document.querySelectorAll("div"); const allRealDivsArray = [...allDivs];

Estoy haciendo un script para elegir un producto (colores, etc.), que funciona en todos los navegadores, excepto en Internet Explorer (11) y Edge .

array.forEach() las opciones de cada parámetro en una matriz y les aplico una función con el método array.forEach() .

Ejemplo para el parámetro de color:

var color_btns = document.querySelectorAll(''#color > p''); color_btns.forEach(function(color) { color.onclick = function () { color_btns.forEach(function(element) { if (element.classList.contains(''selected'')) { element.classList.remove(''selected''); } }); color.classList.add(''selected''); document.querySelector(''#f_color'').value = color.dataset.id; }; });

Obtengo el siguiente resultado en la consola de IE y Edge :

El objeto no admite la propiedad o el método ''forEach''

Después de buscar sobre el problema, aprendí que IE 9 y versiones posteriores deberían admitir esta función. Traté de definir la función por mí mismo sin éxito. Cuando registro la función, se define como una función (con " [native code] " dentro).

.forEach cada .forEach por un for y funciona bastante bien,

  • pero ¿cómo puedo hacer que funcione?
  • ¿Existe un uso específico de forEach() para Internet Explorer y Edge ?

Pensé que era Array.prototype.forEach y que las versiones recientes de IE (y todas las versiones de Edge) lo tenían ...?


El valor de retorno de .querySelectorAll() no es una matriz, es una NodeList . Eso solo se obtuvo recientemente para cada forEach (y compatibilidad con el protocolo de iteración de JavaScript, lo que le permite usarlos como objetivos de notación for-of y spread).

Puede forEach fácilmente para cada forEach fácilmente:

if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) { // Yes, there''s really no need for `Object.defineProperty` here NodeList.prototype.forEach = Array.prototype.forEach; }

La asignación directa está bien en este caso, porque enumerable , configurable y writable debería ser todo true y es una propiedad de valor. (La true enumerable me sorprendió, pero así es como se define de forma nativa en Chrome, Firefox, Edge y Safari).

Cuando NodeList llegó a forEach , también se volvió iterable , lo que significa que puede recorrer el contenido de una NodeList través for-of bucles for-of , y usar una NodeList en otros lugares donde se espera un iterable (por ejemplo, en notación extendida en un inicializador de matriz) .

En la práctica, es probable que un navegador que tiene características que usan iterabilidad (como for-of loops) también proporcione estas características de NodeList , pero para asegurarse de que (tal vez esté transpilando e incluyendo un polyfill para Symbol ), necesita hacer una segunda cosa: agregar una función a su propiedad Symbol.iterator que crea un iterador:

if (typeof Symbol !== "undefined" && Symbol.iterator && typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype[Symbol.iterator]) { Object.defineProperty(NodeList.prototype, Symbol.iterator, { value: Array.prototype[Symbol.itereator], writable: true, configurable: true }); }

Haciendo ambos juntos:

if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) { // Yes, there''s really no need for `Object.defineProperty` here NodeList.prototype.forEach = Array.prototype.forEach; if (typeof Symbol !== "undefined" && Symbol.iterator && !NodeList.prototype[Symbol.iterator]) { Object.defineProperty(NodeList.prototype, Symbol.iterator, { value: Array.prototype[Symbol.itereator], writable: true, configurable: true }); } }

Aquí hay un ejemplo en vivo usando ambos, intente esto en (por ejemplo) IE11 (aunque solo demostrará para cada forEach ), en el que NodeList no tiene estas características de forma nativa:

// Using only ES5 features so this runs on IE11 function log() { if (typeof console !== "undefined" && console.log) { console.log.apply(console, arguments); } } if (typeof NodeList !== "undefined" && NodeList.prototype) { // forEach if (!NodeList.prototype.forEach) { // Yes, there''s really no need for `Object.defineProperty` here console.log("Added forEach"); NodeList.prototype.forEach = Array.prototype.forEach; } // Iterability if (typeof Symbol !== "undefined" && Symbol.iterator && !NodeList.prototype[Symbol.iterator]) { console.log("Added Symbol.iterator"); Object.defineProperty(NodeList.prototype, Symbol.iterator, { value: Array.prototype[Symbol.itereator], writable: true, configurable: true }); } } log("Testing forEach"); document.querySelectorAll(".container div").forEach(function(div) { var html = div.innerHTML; div.innerHTML = html[0].toUpperCase() + html.substring(1).toLowerCase(); }); // Iterable if (typeof Symbol !== "undefined" && Symbol.iterator) { // Using eval here to avoid causing syntax errors on IE11 log("Testing iterability"); eval( ''for (const div of document.querySelectorAll(".container div")) { '' + '' div.style.color = "blue"; '' + ''}'' ); }

<div class="container"> <div>one</div> <div>two</div> <div>three</div> <div>four</div> </div>

La HTMLCollection devuelta por getElementsByTagName (y varias otras API antiguas) no se define como iterable, pero si lo desea, también puede hacer esto para HTMLCollection . Aquí hay un bucle haciendo boty NodeList (si es necesario) y HTMLCollection (si es necesario):

for (const ctor of [typeof NodeList !== "undefined" && NodeList, typeof HTMLCollection !== "undefined" && HTMLCollection]) { if (ctor && ctor.prototype && !ctor.prototype.forEach) { // (Yes, there''s really no need for `Object.defineProperty` here) ctor.prototype.forEach = Array.prototype.forEach; if (typeof Symbol !== "undefined" && Symbol.iterator && !ctor.prototype[Symbol.iterator]) { Object.defineProperty(ctor.prototype, Symbol.iterator, { value: Array.prototype[Symbol.itereator], writable: true, configurable: true }); } } }

Solo tenga en cuenta que HTMLCollection está HTMLCollection , por lo que los cambios que realice en el DOM que afectan lo que está en la colección se reflejarán en la colección de inmediato, lo que podría dar lugar a un comportamiento sorprendente. ( NodeList es una colección desconectada, por lo que ese comportamiento no ocurre).


Si bien puede parecer una matriz, en realidad es una NodeList que no tiene las mismas características que una matriz. Use un bucle for en su lugar

color_btns = document.querySelectorAll(''#color > p''); for (var i = 0; i < color_btns.length; i++) { color_btns[i].onclick = function () { for (var j = 0; j < color_btns.length; j++) { if(color_btns[j].classList.contains(''selected'')) { color_btns[j].classList.remove(''selected''); } } color_btns[i].classList.add(''selected''); document.querySelector(''#f_color'').value = color_btns[i].dataset.id; }; }