Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
[]
- массив. Этот массив не используется вообще.
Он помещается на страницу, потому что использование массива дает вам доступ к прототипам массива, например .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"
Поэтому вы создаете быстрый способ вызова функции forEach
, и вы меняете this
из пустого массива на список всех тегов <a>
и
Ниже приведена ссылка на статью. что мы отказываемся от попыток функционального программирования и каждый раз придерживаемся ручного, встроенного цикла, потому что это решение хакерское и неприглядное.
Я бы сказал, что, хотя .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);
};
Не только slice( )
/ array( )
/ и т. д., чтобы облегчить жизнь людям, которые хотят использовать списки, так же, как они используют массивы (как и должны), но для людей, у которых есть роскошь работы в браузерах ES6 + относительно близких будущее или «трансбинирование» в Вавилоне сегодня, у вас есть встроенные языковые функции, которые делают ненужным этот тип вещей.
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 ];
Супер-чистый и очень полезный. Найдите операторы Rest и Spread ; попробуйте их на сайте BabelJS; если ваш технический стек в порядке, используйте их в производстве с Babel и шаг сборки.
Нет никакой веской причины, чтобы не использовать преобразование из не-массива в массив ... ... просто не делайте беспорядок своего кода, ничего не делая , но вставляя ту же уродливую линию, везде.
Просто быстрое и грязное решение, которое я всегда использую. Я не стал бы трогать прототипы, как хорошую практику. Конечно, есть много способов сделать это лучше, но вы получите эту идею.
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}`);
});
Его можно лучше написать, используя
Array.prototype.forEach.call( document.querySelectorAll('a'), function(el) {
});
. Что такое is document.querySelectorAll('a')
возвращает объект, похожий на массив, но он не наследуется от типа Array
. Поэтому мы вызываем метод forEach
из объекта Array.prototype
с контекстом как значением, возвращаемым document.querySelectorAll('a')
Просто добавьте одну строку:
NodeList.prototype.forEach = HTMLCollection.prototype.forEach = Array.prototype.forEach;
И voila!
document.querySelectorAll('a').forEach(function(el) {
// whatever with the current node
});
Наслаждайтесь: -)
Warning: NodeList - это глобальный класс. Не используйте эту рекомендацию, если вы пишете публичную библиотеку. Однако это очень удобный способ повысить самоэффективность при работе на веб-сайте или приложении node.js.
Метод querySelectorAll
возвращает NodeList
, который похож на массив, но это не совсем массив. Таким образом, у него нет метода forEach
(какие объекты массива наследуются через Array.prototype
).
Так как NodeList
похож на массив, методы массива будут работать на нем, поэтому используя [].forEach.call
, вы вызываете метод Array.prototype.forEach
в контексте NodeList
, как если бы вы могли просто сделать yourNodeList.forEach(/*...*/)
.
Обратите внимание, что пустой литерал массива просто ярлык к расширенной версии, который вы, вероятно, увидите довольно часто:
Array.prototype.forEach.call(/*...*/);
[].forEach.call(['a','b'], cb)
над ['a','b'].forEach(cb)
в повседневных приложениях со стандартными массивами, просто при попытке итерации по структурам, подобным массивам, которые не имеют forEach
на собственном прототипе? Это верно?
– Matt Fletcher
30 January 2015 в 13:16
[].forEach()
:)
– Matt Fletcher
30 January 2015 в 13:23
Другие ответы очень хорошо объяснили этот код, поэтому я просто добавлю предложение.
Это хороший пример кода, который нужно реорганизовать для простоты и ясности. Вместо использования [].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
});
Norguard объяснил ЧТО [].forEach.call()
делает и Джеймс Аллардис ПОЧЕМУ мы это делаем: поскольку querySelectorAll возвращает NodeList
, у которого нет метода forEach ...
Если у вас нет современного браузера, такого как Chrome 51+, Firefox 50+, Opera 38, Safari 10.
Если нет, вы можете добавить 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);
}
};
}
Пустой массив имеет свойство forEach
в своем прототипе, который является объектом Function. (Пустой массив - это простой способ получить ссылку на функцию forEach
, которую имеют все объекты Array
.) Объекты функций, в свою очередь, имеют свойство call
, которое также является функцией. Когда вы вызываете функцию call
функции, она запускает функцию с заданными аргументами. Первый аргумент становится this
в вызываемой функции.
Здесь вы можете найти документацию для функции call
здесь . Документация для forEach
здесь здесь .
[]
всегда возвращает новый массив, он эквивалентен new Array()
, но гарантированно возвращает массив, потому что Array
может быть перезаписан пользователем, тогда как []
не может. Таким образом, это безопасный способ получить прототип Array
, а затем, как описано, call
используется для выполнения функции в узле arraylike (this).
Вызывает функцию с данное значение и аргументы предоставляются отдельно. mdn
[]
на самом деле всегда возвращает массив, а window.Array
может быть перезаписан каким-либо (во всех старых браузерах), так что window.Array.prototype.forEach
может быть перезаписано чем угодно. В обоих случаях нет гарантий безопасности, в браузерах, которые не поддерживают геттеры / сеттеры или герметизацию / замораживание объекта (замораживание, вызывающее проблемы его размножения).
– Norguard
19 April 2015 в 14:31
prototype
или его методов: forEach
.
– Xotic750
19 April 2015 в 20:29
.call
выполняет i> изменение значенияthis
, поэтому вы используетеcall
с функцией forEach. Если forEach выглядит какforEach (fn) { var i = 0; var len = this.length; for (; i < length; i += 1) { fn( this[i], i, this ); }
, то, изменяяthis
, говоряforEach.call( newArrLike )
, означает, что он будет использовать этот новый объект какthis
. – Norguard 17 April 2015 в 16:14console.log(this)
внутри функцииforEach
, я должен получить nodeList, добавленный мной через.call
, потому что я изменил значение этого, однако меня смущает то, чтоthis
равен окну, а не nodeList – Muhammad Saleh 19 April 2015 в 08:12.call
не изменяет значениеthis
внутри того, что вы переходите наforEach
,.call
изменяет значениеthis
внутри forEach i>. Если вы смущены тем, чтоthis
не передается изforEach
в функцию, которую вы хотели вызвать, вы должны искать поведениеthis
в JavaScript. В качестве дополнения, применимого только здесь (и map / filter / reduce), есть второй аргументforEach
, который устанавливаетthis
внутри функцииarr.forEach(fn, thisInFn)
или[].forEach.call(arrLike, fn, thisInFn);
или просто использует.bind
;arr.forEach(fn.bind(thisInFn));
– Norguard 19 April 2015 в 12:03[]
существует как массив, так что вы можете.call
метод.forEach
и изменитьthis
на набор, над которым хотите работать..call
выглядит так:function (thisArg, a, b, c) { var method = this; method(a, b, c); }
, кроме внутренней черной магии, чтобы установитьthis
внутриmethod
равным тому, что вы передали какthisArg
. – Norguard 23 November 2015 в 20:47