[]
jest tablicą.
Ta tablica nie jest w ogóle używana.
Jest umieszczany na stronie, ponieważ użycie tablicy daje dostęp do prototypów tablic, takich jak .forEach
.
To jest po prostu szybsze niż pisanie Array.prototype.forEach.call(...);
Następnie forEach
jest to funkcja, która przyjmuje funkcję jako dane wejściowe ...
[1,2,3].forEach(function (num) { console.log(num); });
... i dla każdego elementu w this
(gdzie this
jest podobny do tablicy, w tym, że ma length
i możesz uzyskać dostęp do jego części jak this[1]
), przekaże trzy rzeczy:
- element w tablicy
- indeks elementu (przeszedłby trzeci element
2
)
- odniesienie do tablicy
Na koniec .call
jest prototypem, który mają funkcje (jest to funkcja wywoływana przez inne funkcje).
.call
weźmie swój pierwszy argument i zastąpi this
wewnątrz zwykłej funkcji tym, co przekazałeś call
, jako pierwszy argument ( undefined
lub null
będzie użyty window
w codziennym JS, lub będzie tym, co przekazałeś, jeśli w "trybie ścisłym"). Reszta argumentów zostanie przekazana do oryginalnej funkcji.
[1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) {
console.log(i + ": " + item);
});
Dlatego tworzysz szybki sposób wywołania forEach
funkcji i zmieniasz this
pustą tablicę na listę wszystkich <a>
tagów, a dla każdego <a>
w kolejności wywołujesz podaną funkcję.
EDYTOWAĆ
Logiczne wnioski / czyszczenie
Poniżej znajduje się link do artykułu sugerującego, że za każdym razem rezygnujemy z prób programowania funkcjonalnego i trzymamy się ręcznego, wbudowanego zapętlania, ponieważ to rozwiązanie jest hakerskie i brzydkie.
Powiedziałbym, że choć .forEach
jest mniej przydatne niż jego odpowiedniki, .map(transformer)
, .filter(predicate)
, .reduce(combiner, initialValue)
, to nadal służy celom kiedy wszystko, co naprawdę chcesz robić to zmieniać świat na zewnątrz (nie array), n-razy, mając jednocześnie dostęp do jednej arr[i]
lub i
.
Jak więc sobie radzić z rozbieżnością, skoro Motto jest wyraźnie utalentowanym i kompetentnym facetem, i chciałbym sobie wyobrazić, że wiem, co robię / dokąd zmierzam (od czasu do czasu ... ... inne razy jest to uczenie się w pierwszej kolejności)?
Odpowiedź jest w rzeczywistości dość prosta i coś, co wujek Bob i Sir Crockford obaj spojrzeliby na siebie z powodu przeoczenia:
posprzątaj to .
function toArray (arrLike) {
return [].slice.call(arrLike);
}
var checked = toArray(checkboxes).filter(isChecked);
checked.forEach(listValues);
Jeśli zastanawiasz się, czy sam musisz to zrobić, odpowiedź może brzmieć nie ...
Dokładnie to robi ... ... każda (?) Biblioteka z funkcjami wyższego rzędu.
Jeśli używasz lodash lub podkreślenia, a nawet jQuery, wszyscy będą mieli sposób na pobranie zestawu elementów i wykonanie akcji n-krotnie.
Jeśli nie używasz czegoś takiego, to jak najbardziej napisz własną.
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);
};
Aktualizacja dla ES6 (ES2015) i nie tylko
Metoda pomocnicza slice( )
/ array( )
/ etc ułatwi życie nie tylko ludziom, którzy chcą używać list tak samo, jak używają tablic (tak jak powinni), ale także osobom, które mają luksus pracy w przeglądarkach ES6 + o stosunkowo bliskiej przyszłości lub „transpilacji” w Babel dzisiaj, masz wbudowane funkcje językowe, które sprawiają, że tego typu rzeczy są niepotrzebne.
function countArgs (...allArgs) {
return allArgs.length;
}
function logArgs (...allArgs) {
return allArgs.forEach(arg => console.log(arg));
}
function extend (subject, ...others) { }
var nodeArray = [ ...nodeList1, ...nodeList2 ];
Super czysty i bardzo przydatny.
Wyszukaj operatory Rest i Spread ; wypróbuj je w witrynie BabelJS; jeśli twój stos technologiczny jest w porządku, użyj go w produkcji z Babel i krokiem budowy.
Nie ma dobrego powodu, aby nie być w stanie korzystać z transformacji z braku tablicy do tablicy ... ... tylko nie rób bałaganu kodzie nic nie robi , ale wklejając że sam brzydki linii, wszędzie.
.call
nie zmienia wartościthis
wewnątrz tego, do czego przekazujeszforEach
,.call
zmienia wartośćthis
wewnątrz forEach . Jeśli jesteś zdezorientowany, dlaczegothis
nie jest przekazywany zforEach
do funkcji, którą chciałeś wywołać, powinieneś sprawdzić zachowaniethis
w JavaScript. Jako dodatek, dotyczy tylko tutaj (i map / filtr / zmniejszenie) jest drugi argumentforEach
, który ustawiathis
wewnątrz funkcjiarr.forEach(fn, thisInFn)
lub[].forEach.call(arrLike, fn, thisInFn);
lub po prostu użyć.bind
;arr.forEach(fn.bind(thisInFn));
[]
to właśnie tam w postaci tablicy, dzięki czemu można.call
się.forEach
metody i zmienićthis
do zestawu, który chcesz zrobić pracować..call
wygląda następująco:function (thisArg, a, b, c) { var method = this; method(a, b, c); }
poza tym, że istnieje wewnętrzna czarna magia, którą można ustawićthis
wewnątrz,method
aby równać się temu, co zdałeś jakothisArg
.[].forEach.call(arr, fn)
będzie działał przez długośćarr
, przeszedłcall
; nie tablica, która jest używana na początkuforEach
(jak podano w pierwszych dwóch zdaniach i omówiono później). Długość początkowej tablicy jest całkowicie nieistotna. Kiedy używasz drugiego argumentuforEach
funkcji, używasz indeksu; tak samo, jakbyś przekazał funkcję bezpośrednio doforEach
zamiastcall
. Gdybyś zarejestrował pierwszy argument, dostałbyś"a", "b", "c"
nie1, 2, 3
, ze względu na to, jak działacall
zamianythis
i jakforEach
działa.querySelectorAll
Metoda zwracaNodeList
, który jest podobny do tablicy, ale nie jest to całkiem tablicą. Dlatego nie maforEach
metody (która dziedziczy przez obiekty tablicyArray.prototype
).Ponieważ a
NodeList
jest podobny do tablicy, metody tablicowe będą na nim faktycznie działać, więc używając[].forEach.call
wywołaniaArray.prototype.forEach
metody w kontekście theNodeList
, tak jakbyś był w stanie to po prostu zrobićyourNodeList.forEach(/*...*/)
.Zwróć uwagę, że pusty literał tablicy to tylko skrót do rozszerzonej wersji, którą prawdopodobnie będziesz często widywać:
Array.prototype.forEach.call(/*...*/);
źródło
[].forEach.call(['a','b'], cb)
ponad['a','b'].forEach(cb)
zastosowań codziennych ze standardowymi tablicami, tylko podczas próby iteracyjne nad tablicy struktury przypominające, które nie mająforEach
własnej prototypu? Czy to jest poprawne?[].forEach()
:)var section = document.querySelectorAll(".section"); section.forEach((item)=>{ console.log(item.offsetTop) })
działa dobrzeforEach
tablice, ale nie obiekty NodeList)Inne odpowiedzi bardzo dobrze wyjaśniły ten kod, więc dodam tylko sugestię.
To jest dobry przykład kodu, który należy przeformułować dla uproszczenia i przejrzystości. Zamiast używać
[].forEach.call()
lub zaArray.prototype.forEach.call()
każdym razem, gdy to robisz, wykonaj z tego prostą funkcję:function forEach( list, callback ) { Array.prototype.forEach.call( list, callback ); }
Teraz możesz wywołać tę funkcję zamiast bardziej skomplikowanego i niejasnego kodu:
forEach( document.querySelectorAll('a'), function( el ) { // whatever with the current node });
źródło
Można go lepiej napisać za pomocą
Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) { });
Co to robi jest
document.querySelectorAll('a')
Zwraca obiekt podobny do tablicy, ale nie dziedziczą odArray
typu. Dlatego wywołujemyforEach
metodę zArray.prototype
obiektu z kontekstem jako wartością zwróconą przezdocument.querySelectorAll('a')
źródło
[].forEach.call( document.querySelectorAll('a'), function(el) { // whatever with the current node });
Jest to w zasadzie to samo, co:
var arr = document.querySelectorAll('a'); arr.forEach(function(el) { // whatever with the current node });
źródło
Chcesz zaktualizować to stare pytanie:
Powód używania
[].foreach.call()
pętli do elementów w nowoczesnych przeglądarkach w większości dobiegł końca. Możemy użyćdocument.querySelectorAll("a").foreach()
bezpośrednio.źródło
Pusta tablica ma
forEach
w swoim prototypie właściwość, która jest obiektem Function. (Pusta tablica jest po prostu łatwym sposobem uzyskania odniesienia doforEach
funkcji, którąArray
mają wszystkie obiekty). Z kolei obiekty funkcji mającall
właściwość, która jest również funkcją. Kiedy wywołujesz funkcję Functioncall
, uruchamia ona funkcję z podanymi argumentami. Pierwszy argument pojawia sięthis
w wywołanej funkcji.Dokumentację
call
funkcji można znaleźć tutaj . Dokumentacja dlaforEach
jest tutaj .źródło
Po prostu dodaj jedną linię:
NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;
I voila!
document.querySelectorAll('a').forEach(function(el) { // whatever with the current node });
Cieszyć się :-)
Ostrzeżenie: NodeList to klasa globalna. Nie używaj tej rekomendacji, jeśli piszesz do biblioteki publicznej. Jest to jednak bardzo wygodny sposób na zwiększenie poczucia własnej skuteczności podczas pracy na stronie internetowej lub aplikacji node.js.
źródło
Tylko szybkie i brudne rozwiązanie, z którego zawsze korzystam. Nie dotykałbym prototypów, po prostu dobra praktyka. Oczywiście istnieje wiele sposobów, aby to poprawić, ale masz pomysł.
const forEach = (array, callback) => { if (!array || !array.length || !callback) return for (var i = 0; i < array.length; i++) { callback(array[i], i); } } forEach(document.querySelectorAll('.a-class'), (item, index) => { console.log(`Item: ${item}, index: ${index}`); });
źródło
[]
zawsze zwraca nową tablicę, jest równoważny z,new Array()
ale gwarantuje, że zwróci tablicę, ponieważArray
może zostać nadpisana przez użytkownika, a[]
nie może. Jest to więc bezpieczny sposób na uzyskanie prototypu programuArray
, który zgodnie z opisemcall
jest używany do wykonania funkcji na liście węzłów typu Arraylike (this).źródło
[]
w rzeczywistości zawsze zwróci tablicę, podczas gdywindow.Array
można go nadpisać czymkolwiek (we wszystkich starych przeglądarkach), więc również możnawindow.Array.prototype.forEach
go nadpisać czymkolwiek. W obu przypadkach nie ma gwarancji bezpieczeństwa w przeglądarkach, które nie obsługują metod pobierających / ustawiających lub uszczelniania / zamrażania obiektów (zamrażanie powoduje własne problemy z rozszerzalnością).prototype
lub jego metod:forEach
.Norguard wyjaśnił CO
[].forEach.call()
robi, a James Allardice DLACZEGO to robimy: ponieważ querySelectorAll zwraca wartośćNodeList
, która nie ma metody forEach ...Chyba że masz nowoczesną przeglądarkę, taką jak Chrome 51+, Firefox 50+, Opera 38, Safari 10.
Jeśli nie, możesz dodać Polyfill :
if (window.NodeList && !NodeList.prototype.forEach) { NodeList.prototype.forEach = function (callback, thisArg) { thisArg = thisArg || window; for (var i = 0; i < this.length; i++) { callback.call(thisArg, this[i], i, this); } }; }
źródło
Wiele dobrych informacji na tej stronie (patrz odpowiedź + odpowiedź + komentarz ), ale ostatnio miałem to samo pytanie co OP i zajęło trochę kopania, aby uzyskać pełny obraz. Oto krótka wersja:
Celem jest użycie
Array
metod na tablicy,NodeList
która sama nie ma tych metod.Starszy wzorzec kooptował metody Array za pośrednictwem
Function.call()
i używał literału tablicowego ([]
), a nieArray.prototype
dlatego, że był krótszy do wpisania:[].forEach.call(document.querySelectorAll('a'), a => {})
Nowszy wzorzec (po ECMAScript 2015) jest używany
Array.from()
:Array.from(document.querySelectorAll('a')).forEach(a => {})
źródło