Что делает [].инструкция foreach.звоните() в JavaScript?
Я смотрел на некоторые фрагменты кода, и я нашел несколько элементов, вызывающих функцию над списком узлов с forEach, примененным к пустому массиву.
например, у меня есть что-то вроде:
[].forEach.call( document.querySelectorAll('a'), function(el) {
// whatever with the current node
});
но я не могу понять, как это работает. Может ли кто-нибудь объяснить мне поведение пустого массива перед forEach и как call работает?
9 ответов:
[]- это массив.
Этот массив не используется вообще.он помещается на страницу, потому что использование массива дает вам доступ к прототипам массива, например
.forEach.это просто быстрее, чем набирать текст
Array.prototype.forEach.call(...);далее
forEach- это функция, которая принимает функцию в качестве входа...[1,2,3].forEach(function (num) { console.log(num); });...и для каждого элемента
this(гдеthisмассив-как, в том, что он имеетlengthи вы можете получить доступ к его части какthis[1]) пройдет три вещи:
- элемент в массиве
- индекс элемента (третий элемент будет проходить
2)- ссылка на массив
и наконец,
.callявляется прототипом, который функции имеют (это функция, которая вызывается на другие функции)..callвозьмет свой первый аргумент и заменитthisвнутри обычной функции с тем, что вы прошлиcall, а первый аргумент (undefinedилиnullиспользоватьwindowв повседневной JS, или будет все, что вы прошли, если в "строгом режиме"). Остальные аргументы будут переданы в исходную функцию.[1, 2, 3].forEach.call(["a", "b", "c"], function (item, i, arr) { console.log(i + ": " + item); }); // 0: "a" // 1: "b" // 2: "c"таким образом, вы создаете быстрый способ вызова , а ты
thisиз пустого массива в список всех<a>теги, и для каждого<a>в порядке, вы вызываете функцию предоставлена.EDIT
Логический Вывод / Очистка
ниже есть ссылка на статью, предлагающую нам отказаться от попыток функционального программирования и придерживаться ручного, встроенного цикла, каждый раз, потому что это решение является взломанным и неприглядным.
я бы сказал, что во время
.forEachменее полезно, чем его коллеги,.map(transformer),.filter(predicate),.reduce(combiner, initialValue), он по-прежнему служит целям, когда все, что вы действительно хотите сделать, это изменить внешний вид мире (не массив), N-раз, при этом имея доступ кarr[i]илиi.Итак, как мы справляемся с неравенством, поскольку девиз явно талантливый и знающий парень, и я хотел бы представить, что я знаю, что я делаю/куда я иду (время от времени... ...в других случаях это головное обучение)?
ответ на самом деле довольно прост, и что-то дядя Боб и Сэр Крокфорд будут оба facepalm, из-за надзор:
его убрать.
function toArray (arrLike) { // or asArray(), or array(), or *whatever* return [].slice.call(arrLike); } var checked = toArray(checkboxes).filter(isChecked); checked.forEach(listValues);теперь, если вы спрашиваете, нужно ли вам это делать, то ответ вполне может быть нет...
Именно это и делается... ...каждый(?) библиотека с функциями более высокого порядка в эти дни.
Если вы используете lodash или подчеркивание или даже jQuery, все они будут иметь способ взять набор элементов и выполнить действие n раз.
Если вы не используете такой вещь, тогда во что бы то ни стало, пиши свою собственную.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); };обновление для ES6 (ES2015) и за его пределами
не только
slice( )/array( )/etc вспомогательный метод собирается сделать жизнь проще для людей, которые хотят использовать списки так же, как они используют массивы (как и должны), но для людей, которые имеют роскошь работать в браузерах ES6+ относительно близкого будущего или "транспилинга" в Babel сегодня, у вас есть встроенные языковые функции, которые делают этот тип вещей ненужный.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 ];супер-чистый и очень полезный.
Посмотрите на остальное и распространение операторы; попробуйте их на сайте BabelJS; если ваш технический стек в порядке, используйте их в производстве с Babel и шагом сборки.
нет никаких веских причин, чтобы не иметь возможности использовать преобразование из не-массива в массив... ...просто не делайте беспорядок из вашего кода ничего не делая но наклеивание той же уродливой линии, везде.
The
querySelectorAllметод возвращает aNodeList, который похож на массив, но это не совсем массив. Поэтому у него нетforEachметод (какие объекты массива наследуются черезArray.prototype).С a
NodeListпохож на массив, методы массива будут фактически работать на нем, поэтому с помощью[].forEach.callвы призываетеArray.prototype.forEachметод в контекстеNodeList, как будто вы были в состоянии просто сделатьyourNodeList.forEach(/*...*/).обратите внимание, что пустой массив literal - это просто ярлык для расширенной версии, который вы, вероятно, тоже увидите довольно часто:
Array.prototype.forEach.call(/*...*/);
другие ответы объяснили этот код очень хорошо, поэтому я просто добавлю предложение.
Это хороший пример кода, который должен быть приведен к простоте и ясности. Вместо того, чтобы использовать
[].forEach.call()илиArray.prototype.forEach.call()каждый раз, когда вы делаете это, сделайте из него простую функцию:function forEach( list, callback ) { Array.prototype.forEach.call( list, callback ); }теперь вы можете вызвать эту функцию вместо более сложного и непонятного кода:
forEach( document.querySelectorAll('a'), function( el ) { // whatever with the current node });
это может быть лучше написано с помощью
Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) { });что это
document.querySelectorAll('a')возвращает объект, похожий на массив, но он не наследуется отArrayтип. Поэтому мы называемforEachметодArray.prototypeобъект с контекстом в качестве значения, возвращаемогоdocument.querySelectorAll('a')
пустой массив имеет свойство
forEachв его прототипе, который является объектом функции. (Пустой массив-это простой способ получить ссылку на элемент вот и всеArrayобъекты.) Функциональные объекты, в свою очередь, имеютcallсвойство, которое также является функцией. При вызове функцииcallфункция, она запускает функцию с заданными аргументами. Первый аргумент становитсяthisв вызываемой функции.вы можете найти документацию
callфункции здесь. Документация дляforEachи здесь.
просто добавьте одну строку:
NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;и вуаля!
document.querySelectorAll('a').forEach(function(el) { // whatever with the current node });наслаждайтесь :-)
предупреждение: NodeList-это глобальный класс. Не используйте эту рекомендацию, если вы пишете публичную библиотеку. Однако это очень удобный способ для повышения самоэффективности при работе на сайте или узле.js app.
просто быстрое и грязное решение, которое я всегда использую. Я бы не стал трогать прототипы, просто как хорошая практика. Конечно, есть много способов сделать это лучше, но вы получите идею.
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}`); });
[]всегда возвращает новый массив, это эквивалентноnew Array()но гарантированно возвращает массив, потому чтоArrayможет быть перезаписан пользователем, тогда как[]не может. Так что это безопасный способ получить прототипArray, тогда как описано,callиспользуется для выполнения функции в arraylike nodelist (this).вызывает функцию с заданным значением и аргументами индивидуально. mdn
Norguard объяснил что
[].forEach.call()и Джеймс Аллардиспочему мы делаем это: потому что querySelectorAll возвращает aNodeListэто не имеет метода forEach...Если у вас нет современного браузера, такого как Chrome 51+, Firefox 50+, Opera 38, Safari 10.
Если нет, вы можете добавить полифилл:
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); } }; }