[]
é uma matriz.
Essa matriz não é usada.
Está sendo colocado na página, porque o uso de uma matriz fornece acesso a protótipos de matriz, como .forEach
.
Isso é apenas mais rápido do que digitar Array.prototype.forEach.call(...);
Em seguida, forEach
é uma função que assume uma função como entrada ...
[1,2,3].forEach(function (num) { console.log(num); });
... e para cada elemento em this
(onde this
é do tipo matriz, na medida em que possui um length
e você pode acessar suas partes como this[1]
), ele passa três coisas:
- o elemento na matriz
- o índice do elemento (o terceiro elemento passaria
2
)
- uma referência à matriz
Por fim, .call
é um protótipo que possui funções (é uma função que é chamada em outras funções).
.call
pegará seu primeiro argumento e substituirá this
dentro da função regular o que você passou call
, como o primeiro argumento ( undefined
ou null
será usado window
no JS diário, ou será o que você passou, se estiver no "modo estrito"). O restante dos argumentos será passado para a função original.
[1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) {
console.log(i + ": " + item);
});
// 0: "a"
// 1: "b"
// 2: "c"
Portanto, você está criando uma maneira rápida de chamar a forEach
função e está mudando this
da matriz vazia para uma lista de todas as <a>
tags e, para cada <a>
ordem, está chamando a função fornecida.
EDITAR
Conclusão Lógica / Limpeza
Abaixo, há um link para um artigo sugerindo que descartemos as tentativas de programação funcional, e seguimos o loop inline manual todas as vezes, porque essa solução é um hack-ish e desagradável.
Eu diria que, enquanto .forEach
é menos útil do que suas contrapartes, .map(transformer)
, .filter(predicate)
, .reduce(combiner, initialValue)
, ainda serve a propósitos quando tudo que você realmente quer fazer é modificar o mundo exterior (não a matriz), N-vezes, ao ter acesso a qualquer arr[i]
ou i
.
Então, como lidamos com a disparidade, já que o Lema é claramente um cara talentoso e experiente, e eu gostaria de imaginar que sei o que estou fazendo / para onde estou indo (de vez em quando ... vezes que é o primeiro aprendizado)?
A resposta é realmente bastante simples, e algo que o tio Bob e Sir Crockford enfrentariam, devido à supervisão:
limpe-o .
function toArray (arrLike) { // or asArray(), or array(), or *whatever*
return [].slice.call(arrLike);
}
var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);
Agora, se você está questionando se precisa fazer isso, você mesmo, a resposta pode não ser ...
exatamente isso é feito por ... ... todas as bibliotecas (?) Com recursos de ordem superior atualmente.
Se você estiver usando lodash, sublinhado ou até jQuery, todos terão uma maneira de pegar um conjunto de elementos e executar uma ação n vezes.
Se você não estiver usando uma coisa dessas, escreva por conta própria.
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);
};
Atualização para ES6 (ES2015) e além
Não apenas o método auxiliar slice( )
/ array( )
/ etc facilitará a vida das pessoas que desejam usar as listas da mesma forma que usam matrizes (como deveriam), mas também para as pessoas que têm o luxo de operar nos navegadores ES6 + dos relativamente próximos. No futuro, ou de "transpilar" hoje em Babel, você tem recursos de linguagem incorporados, que tornam esse tipo de coisa desnecessário.
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 ];
Super limpo e muito útil.
Procure os operadores Descansar e Espalhar ; experimentá-los no site BabelJS; se sua pilha de tecnologia estiver em ordem, use-a em produção com Babel e uma etapa de construção.
Não há uma boa razão para não poder usar a transformação de não array em array ... ... apenas não bagunce seu código sem fazer nada além de colar a mesma linha feia em todos os lugares.
.call
não alterar o valorthis
, que é por isso que você está usandocall
com o forEach. Se forEach se pareceforEach (fn) { var i = 0; var len = this.length; for (; i < length; i += 1) { fn( this[i], i, this ); }
, alterandothis
dizendoforEach.call( newArrLike )
significa que ele usará esse novo objeto comothis
..call
não altera o valor dethis
dentro do que você passaforEach
,.call
altera o valor dethis
dentro de forEach . Se você está confuso sobre o motivo pelo qualthis
não é passadoforEach
para a função que você queria chamar, você deve procurar o comportamento dothis
JavaScript. Como um aditivo, aplicável apenas aqui (e mapa / filtro / reduzir), existe um segundo argumento paraforEach
, que definethis
no interior da funçãoarr.forEach(fn, thisInFn)
ou[].forEach.call(arrLike, fn, thisInFn);
ou uso apenas.bind
;arr.forEach(fn.bind(thisInFn));
[]
existe apenas como uma matriz, para que você possa usar.call
o.forEach
método e alterethis
para o conjunto em que deseja trabalhar..call
se parece com isso:function (thisArg, a, b, c) { var method = this; method(a, b, c); }
exceto que há magia negra interna para definirthis
dentromethod
para igualar o que você passou comothisArg
.O
querySelectorAll
método retorna aNodeList
, que é semelhante a uma matriz, mas não é exatamente uma matriz. Portanto, ele não possui umforEach
método (que objetos de matriz herdam viaArray.prototype
).Como a
NodeList
é semelhante a uma matriz, os métodos da matriz realmente funcionarão nela; portanto, usando[].forEach.call
você está invocando oArray.prototype.forEach
método no contexto daNodeList
, como se você pudesse simplesmente fazê-loyourNodeList.forEach(/*...*/)
.Observe que o literal da matriz vazia é apenas um atalho para a versão expandida, que você provavelmente verá com bastante frequência:
fonte
[].forEach.call(['a','b'], cb)
mais['a','b'].forEach(cb)
em aplicações cotidianas com matrizes padrão, apenas quando se tenta iterate sobre array-como estruturas que não têmforEach
em seu próprio protótipo? Isso está correto?[].forEach()
:)var section = document.querySelectorAll(".section"); section.forEach((item)=>{ console.log(item.offsetTop) })
funciona bemforEach
em matrizes, mas não objetos NodeList)As outras respostas explicaram muito bem esse código, então adicionarei uma sugestão.
Este é um bom exemplo de código que deve ser refatorado para simplicidade e clareza. Em vez de usar
[].forEach.call()
ouArray.prototype.forEach.call()
toda vez que você fizer isso, crie uma função simples:Agora você pode chamar esta função em vez do código mais complicado e obscuro:
fonte
Pode ser melhor escrito usando
O que é does é
document.querySelectorAll('a')
retorna um objeto semelhante a uma matriz, mas não herda doArray
tipo. Então, chamamos oforEach
método doArray.prototype
objeto com o contexto como o valor retornado pordocument.querySelectorAll('a')
fonte
É basicamente o mesmo que:
fonte
Deseja atualizar esta pergunta antiga:
O motivo para usar o
[].foreach.call()
loop através de elementos nos navegadores modernos acabou principalmente. Nós podemos usardocument.querySelectorAll("a").foreach()
diretamente.fonte
Uma matriz vazia possui uma propriedade
forEach
em seu protótipo, que é um objeto Function. (A matriz vazia é apenas uma maneira fácil de obter uma referência àforEach
função que todos osArray
objetos possuem.) Os objetos de função, por sua vez, possuem umacall
propriedade que também é uma função. Quando você invoca a função de uma Funçãocall
, ela executa a função com os argumentos fornecidos. O primeiro argumento se tornathis
na função chamada.Você pode encontrar documentação para a
call
função aqui . A documentação paraforEach
está aqui .fonte
Basta adicionar uma linha:
E pronto!
Aproveitar :-)
Aviso: NodeList é uma classe global. Não use esta recomendação se estiver escrevendo uma biblioteca pública. No entanto, é uma maneira muito conveniente de aumentar a auto-eficácia quando você trabalha no site ou no aplicativo node.js.
fonte
Apenas uma solução rápida e suja que eu sempre uso. Eu não tocaria em protótipos, assim como boas práticas. Claro, existem várias maneiras de melhorar isso, mas você entendeu.
fonte
[]
sempre retorna uma nova matriz, é equivalente a,new Array()
mas é garantido, que retorne uma matriz, poisArray
pode ser sobrescrita pelo usuário e[]
não pode. Portanto, esta é uma maneira segura de obter o protótipo deArray
, então, conforme descrito,call
é usado para executar a função no nodelist de matriz (this).fonte
[]
o fato sempre retorne uma matriz, o whilewindow.Array
pode ser substituído por qualquer coisa (em todos os navegadores antigos), assim também podewindow.Array.prototype.forEach
ser substituído por qualquer coisa. Nos dois casos, não há garantia de segurança em navegadores que não suportam getters / setters ou vedação / congelamento de objetos (o congelamento causa seus próprios problemas de extensibilidade).prototype
ou é métodos:forEach
.Norguard explicou o que
[].forEach.call()
faz e James Allardice POR QUE o fazemos: porque querySelectorAll retorna umNodeList
que não possui um método forEach ...A menos que você tenha um navegador moderno como o Chrome 51+, Firefox 50+, Opera 38, Safari 10.
Caso contrário, você pode adicionar um Polyfill :
fonte
Muitas informações boas nesta página (consulte resposta + resposta + comentário ), mas recentemente tive a mesma pergunta que o OP, e demorou algumas escavações para obter uma imagem completa. Então, aqui está uma versão curta:
O objetivo é usar
Array
métodos em uma matrizNodeList
que não possua esses métodos.Um padrão mais antigo cooptava os métodos de Array via
Function.call()
e usava uma matriz literal ([]
) em vez deArray.prototype
ser mais curta para digitar:Um padrão mais recente (pós ECMAScript 2015) é usar
Array.from()
:fonte