[]
es una matriz
Esta matriz no se usa en absoluto.
Se está poniendo en la página, porque el uso de una matriz le da acceso a prototipos de matriz, como .forEach
.
Esto es más rápido que escribir Array.prototype.forEach.call(...);
A continuación, forEach
hay una función que toma una función como entrada ...
[1,2,3].forEach(function (num) { console.log(num); });
... y para cada elemento en this
(donde this
es como una matriz, en el sentido de que tiene un length
y puede acceder a sus partes como this[1]
) pasará tres cosas:
- el elemento en la matriz
- el índice del elemento (pasaría el tercer elemento
2
)
- una referencia a la matriz
Por último, .call
es un prototipo que tienen funciones (es una función que se llama a otras funciones).
.call
tomará su primer argumento y lo reemplazará this
dentro de la función regular con lo que haya pasado call
, como primer argumento ( undefined
o null
lo usará window
en JS cotidiano, o será lo que haya pasado, si está en "modo estricto"). El resto de los argumentos se pasarán a la función original.
[1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) {
console.log(i + ": " + item);
});
// 0: "a"
// 1: "b"
// 2: "c"
Por lo tanto, está creando una forma rápida de llamar a la forEach
función, y está cambiando this
de la matriz vacía a una lista de todas las <a>
etiquetas, y para cada <a>
orden, está llamando a la función proporcionada.
EDITAR
Conclusión lógica / limpieza
A continuación, hay un enlace a un artículo que sugiere que descartemos los intentos de programación funcional y nos apeguemos al bucle manual, en línea, siempre, porque esta solución es hack-ish y antiestética.
Yo diría que, si bien .forEach
es menos útil que sus homólogos, .map(transformer)
, .filter(predicate)
, .reduce(combiner, initialValue)
, todavía sirve los propósitos cuando todo lo que realmente quiere hacer es modificar el mundo exterior (no la matriz), n-veces, mientras que tener acceso a cualquiera arr[i]
o i
.
Entonces, ¿cómo lidiamos con la disparidad, ya que Motto es claramente un tipo talentoso y conocedor, y me gustaría imaginar que sé lo que estoy haciendo / a dónde voy (de vez en cuando ... ... otro veces es el aprendizaje de cabeza)?
La respuesta es en realidad bastante simple, y algo que tío Bob y Sir Crockford se enfrentarían a ambos, debido a la supervisión:
limpiarlo .
function toArray (arrLike) { // or asArray(), or array(), or *whatever*
return [].slice.call(arrLike);
}
var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);
Ahora, si se pregunta si necesita hacer esto, usted mismo, la respuesta puede ser no ...
Esto es exactamente lo que hacen ... ... todas las (?) Bibliotecas con características de orden superior en estos días.
Si está usando lodash o subrayado o incluso jQuery, todos tendrán una forma de tomar un conjunto de elementos y realizar una acción n veces.
Si no estás usando algo así, entonces, por supuesto, escribe el tuyo.
lib.array = (arrLike, start, end) => [].slice.call(arrLike, start, end);
lib.extend = function (subject) {
var others = lib.array(arguments, 1);
return others.reduce(appendKeys, subject);
};
Actualización para ES6 (ES2015) y más allá
No solo un método auxiliar slice( )
/ array( )
/ etc facilitará la vida de las personas que desean usar listas tal como usan las matrices (como deberían), sino también para las personas que tienen el lujo de operar en navegadores ES6 + de usuarios relativamente cercanos. futuro, o de "transpilar" en Babel hoy, tiene características de lenguaje incorporadas, que hacen innecesario este tipo de cosas.
function countArgs (...allArgs) {
return allArgs.length;
}
function logArgs (...allArgs) {
return allArgs.forEach(arg => console.log(arg));
}
function extend (subject, ...others) { /* return ... */ }
var nodeArray = [ ...nodeList1, ...nodeList2 ];
Súper limpio y muy útil.
Busque los operadores Rest and Spread ; pruébelos en el sitio de BabelJS; Si su pila tecnológica está en orden, úsela en producción con Babel y un paso de compilación.
No hay una buena razón para no poder usar la transformación de no matriz a matriz ... ... simplemente no ensucie su código haciendo nada más que pegar esa misma línea fea, en todas partes.
.call
no cambiar el valor dethis
, por lo que usted está utilizandocall
con el forEach. Si forEach se ve asíforEach (fn) { var i = 0; var len = this.length; for (; i < length; i += 1) { fn( this[i], i, this ); }
, al cambiarthis
diciendo,forEach.call( newArrLike )
significa que usará ese nuevo objeto comothis
..call
no cambia el valor delthis
interior de lo que le pasaforEach
,.call
cambia el valor delthis
interior de forEach . Si no está seguro de por quéthis
no se pasa deforEach
la función a la que desea llamar, debe buscar el comportamientothis
en JavaScript. Como una adición, aplicable solamente aquí (y mapa / filtro / reducir), hay un segundo argumento paraforEach
, que establecethis
dentro de la funciónarr.forEach(fn, thisInFn)
o[].forEach.call(arrLike, fn, thisInFn);
o uso justo.bind
;arr.forEach(fn.bind(thisInFn));
[]
solo está allí como una matriz, para que pueda usar.call
el.forEach
método y cambiarthis
el conjunto al que desea trabajar..call
se ve así:function (thisArg, a, b, c) { var method = this; method(a, b, c); }
excepto que hay magia negra interna para establecerthis
dentro demethod
igual a lo que pasóthisArg
.El
querySelectorAll
método devuelve aNodeList
, que es similar a una matriz, pero no es exactamente una matriz. Por lo tanto, no tiene unforEach
método (que los objetos de matriz heredan a través deArray.prototype
).Dado que a
NodeList
es similar a una matriz, los métodos de matriz realmente funcionarán en ella, por lo que al usarlos[].forEach.call
invocas elArray.prototype.forEach
método en el contexto de laNodeList
, como si hubieras podido hacerlo simplementeyourNodeList.forEach(/*...*/)
.Tenga en cuenta que el literal de matriz vacía es solo un acceso directo a la versión expandida, que probablemente también verá con bastante frecuencia:
fuente
[].forEach.call(['a','b'], cb)
más['a','b'].forEach(cb)
en aplicaciones cotidianas con matrices estándar, solo cuando se intenta iterar sobre estructuras similares a matrices que no tienenforEach
su propio prototipo? ¿Es eso correcto?[].forEach()
:)var section = document.querySelectorAll(".section"); section.forEach((item)=>{ console.log(item.offsetTop) })
funciona bienforEach
con matrices, pero no con objetos NodeList)Las otras respuestas han explicado este código muy bien, así que solo agregaré una sugerencia.
Este es un buen ejemplo de código que debe ser refactorizado por simplicidad y claridad. En lugar de usar
[].forEach.call()
oArray.prototype.forEach.call()
cada vez que haga esto, realice una función simple:Ahora puede llamar a esta función en lugar del código más complicado y oscuro:
fuente
Se puede escribir mejor usando
Lo que hace es
document.querySelectorAll('a')
devolver un objeto similar a una matriz, pero no hereda delArray
tipo. Entonces llamamos alforEach
método desde elArray.prototype
objeto con el contexto como el valor devuelto pordocument.querySelectorAll('a')
fuente
Básicamente es lo mismo que:
fuente
Quiere actualizar esta vieja pregunta:
La razón para usar
[].foreach.call()
para recorrer elementos en los navegadores modernos ha terminado. Podemos usardocument.querySelectorAll("a").foreach()
directamente.fuente
Una matriz vacía tiene una propiedad
forEach
en su prototipo que es un objeto Function. (La matriz vacía es solo una manera fácil de obtener una referencia a laforEach
función que tienen todos losArray
objetos). Los objetos de función, a su vez, tienen unacall
propiedad que también es una función. Cuando invocas la función de una Funcióncall
, ejecuta la función con los argumentos dados. El primer argumento se conviertethis
en la función llamada.Puede encontrar documentación para la
call
función aquí . La documentación paraforEach
está aquí .fuente
Solo agrega una línea:
¡Y voilá!
Disfruta :—)
Advertencia: NodeList es una clase global. No use esta recomendación si escribe una biblioteca pública. Sin embargo, es una forma muy conveniente de aumentar la autoeficacia cuando trabaja en el sitio web o en la aplicación node.js.
fuente
Solo una solución rápida y sucia que siempre uso. No tocaría prototipos, como buena práctica. Por supuesto, hay muchas maneras de mejorar esto, pero se entiende la idea.
fuente
[]
siempre devuelve una nueva matriz, es equivalentenew Array()
pero se garantiza que devolverá una matriz porqueArray
el usuario podría sobrescribirla mientras[]
que no puede. Entonces, esta es una forma segura de obtener el prototipo deArray
, luego, como se describe,call
se utiliza para ejecutar la función en la lista de nodos de matriz (esto).fuente
[]
, de hecho, siempre devolverá una matriz, mientras quewindow.Array
puede sobrescribirse con cualquier cosa (en todos los navegadores antiguos), también puedewindow.Array.prototype.forEach
sobrescribirse con cualquier cosa. No hay garantía de seguridad en ninguno de los casos, en los navegadores que no admiten getters / setters o sellado / congelación de objetos (la congelación causa sus propios problemas de extensibilidad).prototype
o métodos de TI:forEach
.Norguard explicó QUÉ
[].forEach.call()
hace y James Allardice POR QUÉ lo hacemos: porque querySelectorAll devuelve unNodeList
que no tiene un método forEach ...A menos que tenga un navegador moderno como Chrome 51+, Firefox 50+, Opera 38, Safari 10.
Si no, puede agregar un Polyfill :
fuente
Mucha información buena en esta página (ver respuesta + respuesta + comentario ), pero recientemente tuve la misma pregunta que el OP, y me tomó un poco de tiempo para obtener la imagen completa. Entonces, aquí hay una versión corta:
El objetivo es usar
Array
métodos en una matrizNodeList
que no tenga esos métodos en sí.Un patrón anterior cooptó los métodos de Array a través de
Function.call()
, y usó una matriz literal ([]
) en lugar deArray.prototype
porque era más corto de escribir:Un patrón más nuevo (post ECMAScript 2015) es usar
Array.from()
:fuente