diff options
Diffstat (limited to 'files/ru/web/javascript/reference/global_objects/array/foreach')
-rw-r--r-- | files/ru/web/javascript/reference/global_objects/array/foreach/index.html | 388 |
1 files changed, 388 insertions, 0 deletions
diff --git a/files/ru/web/javascript/reference/global_objects/array/foreach/index.html b/files/ru/web/javascript/reference/global_objects/array/foreach/index.html new file mode 100644 index 0000000000..3787dc7e84 --- /dev/null +++ b/files/ru/web/javascript/reference/global_objects/array/foreach/index.html @@ -0,0 +1,388 @@ +--- +title: Array.prototype.forEach() +slug: Web/JavaScript/Reference/Global_Objects/Array/forEach +tags: + - Array + - ECMAScript5 + - JavaScript + - Method + - Prototype + - Reference + - forEach + - polyfill +translation_of: Web/JavaScript/Reference/Global_Objects/Array/forEach +--- +<div>{{JSRef("Global_Objects", "Array")}}</div> + +<p>Метод <code><strong>forEach()</strong></code> выполняет указанную функцию один раз для каждого элемента в массиве.</p> + +<div>{{EmbedInteractiveExample("pages/js/array-foreach.html")}}</div> + +<p class="hidden">Источник этого интерактивного примера хранится в GitHub. Если вы хотите внести вклад в проект интерактивных примеров, пожалуйста, клонируйте <a href="https://github.com/mdn/interactive-examples"> https://github.com/mdn/interactive-examples</a> и отправьте нам pull request.</p> + +<h2 id="Syntax" name="Syntax">Синтаксис</h2> + +<pre><var>arr</var>.forEach(function <var>callback(currentValue, index, array) { + //your iterator +}</var>[, <var>thisArg</var>]);</pre> + +<h3 id="Parameters" name="Parameters">Параметры</h3> + +<dl> + <dt><code>callback</code></dt> + <dd>Функция, которая будет вызвана для каждого элемента массива. Она принимает от одного до трех аргументов:</dd> + <dd> + <dl> + <dt><code>currentValue</code></dt> + <dd>Текущий обрабатываемый элемент в массиве.</dd> + <dt><code>index</code>{{optional_inline}}</dt> + <dd>Индекс текущего обрабатываемого элемента в массиве.</dd> + <dt><code>array</code>{{optional_inline}}</dt> + <dd>Массив, по которому осуществляется проход.</dd> + </dl> + </dd> + <dt><code>thisArg</code></dt> + <dd>Необязательный параметр. Значение, используемое в качестве <code>this</code> при вызове функции <code>callback</code>.</dd> +</dl> + +<h3 id="Возвращаемое_значение">Возвращаемое значение</h3> + +<p>{{jsxref("undefined")}}.</p> + +<h2 id="Description" name="Description">Описание</h2> + +<p>Метод <code>forEach()</code> выполняет функцию <code>callback</code> один раз для каждого элемента, находящегося в массиве в порядке возрастания. Она не будет вызвана для удалённых или пропущенных элементов массива. Однако, она будет вызвана для элементов, которые присутствуют в массиве и имеют значение {{jsxref("Global_Objects/undefined", "undefined")}}.</p> + +<p>Функция <code>callback</code> будет вызвана с <strong>тремя аргументами</strong>:</p> + +<ul> + <li>значение элемента (<strong>value</strong>)</li> + <li>индекс элемента (<strong>index</strong>)</li> + <li>массив, по которому осуществляется проход (<strong>array</strong>)</li> +</ul> + +<p>Если в метод <code>forEach()</code> был передан параметр <code>thisArg</code>, при вызове <code>callback</code> он будет использоваться в качестве значения <code>this</code>. В противном случае, в качестве значения <code>this</code> будет использоваться значение {{jsxref("Global_Objects/undefined", "undefined")}}. В конечном итоге, значение <code>this</code>, наблюдаемое из функции <code>callback</code>, определяется согласно {{jsxref('Operators/this', 'обычным правилам определения <code>this</code>, видимого из функции')}}.</p> + +<p>Диапазон элементов, обрабатываемых методом <code>forEach()</code>, устанавливается до первого вызова функции <code>callback</code>. Элементы, добавленные в массив после начала выполнения метода <code>forEach()</code>, не будут посещены функцией <code>callback</code>. Если существующие элементы массива изменятся, значения, переданные в функцию <code>callback</code>, будут значениями на тот момент времени, когда метод <code>forEach()</code> посетит их; удалённые элементы посещены не будут. Если уже посещённые элементы удаляются во время итерации (например, с помощью {{jsxref("Array.prototype.shift()", "shift()")}}), последующие элементы будут пропущены. ({{jsxref('Global_Objects/Array/forEach', 'Смотри пример ниже', 'Модификация_массива_во_время_итерации')}})</p> + +<div class="note"> +<p><strong>Примечание:</strong> Не существует способа остановить или прервать цикл <code>forEach()</code> кроме как выбрасыванием исключения. Если вам необходимо такое поведение, метод <code>forEach()</code> неправильный выбор.</p> + +<p>Досрочное прекращение может быть достигнуто с:</p> + +<ul> + <li>Простой цикл {{jsxref('Statements/for', 'for')}}</li> + <li>Циклы {{jsxref('Statements/for...of', 'for...of')}} / {{jsxref('Statements/for...in', 'for...in')}}</li> + <li>{{jsxref("Array.prototype.every()")}}</li> + <li>{{jsxref("Array.prototype.some()")}}</li> + <li>{{jsxref("Array.prototype.find()")}}</li> + <li>{{jsxref("Array.prototype.findIndex()")}}</li> +</ul> + +<p>Если нужно протестировать элементы массива на условие и нужно вернуть булево значение, вы можете воспользоваться методами {{jsxref("Array.prototype.every()", "every()")}}, {{jsxref("Array.prototype.some()", "some()")}}, {{jsxref("Array.prototype.find()", "find()")}} или {{jsxref("Array.prototype.findIndex()", "findIndex()")}}.</p> + +<p>Метод <code>forEach()</code> выполняет функцию <code>callback</code> один раз для каждого элемента массива; в отличие от методов {{jsxref("Array.prototype.every()", "every()")}} и {{jsxref("Array.prototype.some()", "some()")}}, он всегда возвращает значение {{jsxref("Global_Objects/undefined", "undefined")}}.</p> +</div> + +<h2 id="Examples" name="Examples">Примеры</h2> + +<h3 id="sparseArray" name="sparseArray">Нет операции для неинициализированных значений (разреженные массивы)</h3> + +<pre class="brush: js">const arraySparse = [1,3,,7] +let numCallbackRuns = 0 + +arraySparse.forEach((element) => { + console.log(element) + numCallbackRuns++ +}) + +console.log("numCallbackRuns: ", numCallbackRuns) + +// 1 +// 3 +// 7 +// numCallbackRuns: 3 +// комментарий: как вы видите пропущенное значение между 3 и 7 не вызывало функцию callback.</pre> + +<h3 id="Конвертируем_цикл_for_в_forEach">Конвертируем цикл for в forEach</h3> + +<pre class="brush:js">const items = ['item1', 'item2', 'item3'] +const copy = [] + +// до +for (let i = 0; i < items.length; i++) { + copy.push(items[i]) +} + +// после +items.forEach(function(item){ + copy.push(item) +}) +</pre> + +<h3 id="Printing_the_contents_of_an_array" name="Printing_the_contents_of_an_array">Печать содержимого массива</h3> + +<div class="blockIndicator note"> +<p><strong>Примечание:</strong> Для отображения содержимого массива в консоли вы можете использовать <a href="/ru/docs/Web/API/Console/table" title="Отображает табличные данные в виде таблицы"><code>console.table()</code></a>, который выводит отформатированную версию массива.</p> + +<p>Следующий пример иллюстрирует альтернативный подход, использующий <code>forEach()</code>.</p> +</div> + +<p>Следующий код выводит каждый элемент массива на новой строке журнала:</p> + +<pre class="brush: js">function logArrayElements(element, index, array) { + console.log('a[' + index + '] = ' + element); +} + +// Обратите внимание на пропуск по индексу 2, там нет элемента, поэтому он не посещается +[2, 5, , 9].forEach(logArrayElements); +// логи: +// a[0] = 2 +// a[1] = 5 +// a[3] = 9 +</pre> + +<h3 id="Использование_thisArg">Использование <code><var>thisArg</var></code></h3> + +<p>Следующий (надуманный) пример обновляет свойства объекта, когда перебирает записи массива:</p> + +<pre class="brush:js">function Counter() { + this.sum = 0 + this.count = 0 +} +Counter.prototype.add = function(array) { + array.forEach((entry) => { + this.sum += entry + ++this.count + }, this) + // ^---- Note +} + +const obj = new Counter() +obj.add([2, 5, 9]) +obj.count +// 3 +obj.sum +// 16 +</pre> + +<p>Поскольку в <code>forEach()</code>передан параметр <code><var>thisArg</var></code> (<code>this</code>), он затем передаётся в <code><var>callback</var></code> при каждом вызове. И callback использует его в качестве собственного значения <code>this</code>.</p> + +<div class="note"> +<p><strong>Примечание:</strong> Если при передаче callback функции используется {{jsxref('Functions/Arrow_functions', 'выражение стрелочной функции')}}, параметр <code><var>thisArg</var></code> может быть опущен, так как все стрелочные функции лексически привязываются к значению{{jsxref("Operators/this", "this")}}.</p> +</div> + +<h3 id="Breaking_a_loop" name="Breaking_a_loop">Прерывание цикла</h3> + +<p>Следующий код использует {{jsxref("Array.prototype.every()")}} для логирования содержимого массива и останавливается при превышении значением заданного порогового значения <code>THRESHOLD</code>.</p> + +<pre class="brush: js">var THRESHOLD = 12; +var v = [5, 2, 16, 4, 3, 18, 20]; +var res; + +res = v.every(function(element, index, array) { + console.log('element:', element); + if (element >= THRESHOLD) { + return false; + } + + return true; +}); +console.log('res:', res); +// логи: +// element: 5 +// element: 2 +// element: 16 +// res: false + +res = v.some(function(element, index, array) { + console.log('element:', element); + if (element >= THRESHOLD) { + return true; + } + + return false; +}); +console.log('res:', res); +// логи: +// element: 5 +// element: 2 +// element: 16 +// res: true +</pre> + +<h3 id="An_object_copy_function" name="An_object_copy_function">Функция копирования объекта</h3> + +<p>Следующий код создаёт копию переданного объекта. Существует несколько способов создания копии объекта, и это один из них. Он позволяет понять, каким образом работает <code>Array.prototype.forEach()</code>, используя функции мета-свойств <code>Object.*</code> из ECMAScript 5.</p> + +<pre class="brush: js">function copy(o) { + var copy = Object.create(Object.getPrototypeOf(o)); + var propNames = Object.getOwnPropertyNames(o); + + propNames.forEach(function(name) { + var desc = Object.getOwnPropertyDescriptor(o, name); + Object.defineProperty(copy, name, desc); + }); + + return copy; +} + +var o1 = { a: 1, b: 2 }; +var o2 = copy(o1); // теперь o2 выглядит также, как и o1 +</pre> + +<h3 id="Модификация_массива_во_время_итерации">Модификация массива во время итерации</h3> + +<p>В следующем примере в лог выводится <code>"one"</code>, <code>"two"</code>, <code>"four"</code>.</p> + +<p>При достижении записи, содержащей значение <code>'two'</code>, первая запись всего массива удаляется, в результате чего все оставшиеся записи перемещаются на одну позицию вверх. Поскольку элемент <code>'four'</code> теперь находится на более ранней позиции в массиве, <code>'three'</code> будет пропущен.</p> + +<p><code>forEach()</code> не делает копию массива перед итерацией.</p> + +<pre class="brush:js">let words = ['one', 'two', 'three', 'four'] +words.forEach((word) => { + console.log(word) + if (word === 'two') { + words.shift() + } +}) +// one +// two +// four +</pre> + +<h3 id="Выравнивание_уплощение_массива">Выравнивание (уплощение) массива</h3> + +<p>Следующий пример приведен только для целей обучения. Если вы хотите выравнять массив с помощью встроенных методов, вы можете использовать {{jsxref("Array.prototype.flat()")}}</p> + +<pre class="brush: js">function flatten(arr) { + const result = [] + + arr.forEach((i) => { + if (Array.isArray(i)) { + result.push(...flatten(i)) + } else { + result.push(i) + } + }) + + return result +} + +// Usage +const nested = [1, 2, 3, [4, 5, [6, 7], 8, 9]] + +flatten(nested) // [1, 2, 3, 4, 5, 6, 7, 8, 9] +</pre> + +<h2 id="Polyfill" name="Polyfill">Полифилл</h2> + +<p>Метод <code>forEach()</code> был добавлен к стандарту ECMA-262 в 5-м издании; поэтому он может отсутствовать в других реализациях стандарта. Вы можете работать с ним, добавив следующий код в начало ваших скриптов, он позволяет использовать <code>forEach()</code> в реализациях, которые не поддерживают этот метод. Этот алгоритм является точно тем, что описан в ECMA-262 5-го издания; он предполагает, что {{jsxref("Object")}} и {{jsxref("TypeError")}} имеют свои первоначальные значения и что <code>callback.call</code> вычисляется в оригинальное значение {{jsxref("Function.prototype.call()")}}.</p> + +<pre class="brush: js">// Шаги алгоритма ECMA-262, 5-е издание, 15.4.4.18 +// Ссылка (en): http://es5.github.io/#x15.4.4.18 +// Ссылка (ru): http://es5.javascript.ru/x15.4.html#x15.4.4.18 +if (!Array.prototype.forEach) { + + Array.prototype.forEach = function (callback, thisArg) { + + var T, k; + + if (this == null) { + throw new TypeError(' this is null or not defined'); + } + + // 1. Положим O равным результату вызова ToObject passing the |this| value as the argument. + var O = Object(this); + + // 2. Положим lenValue равным результату вызова внутреннего метода Get объекта O с аргументом "length". + // 3. Положим len равным ToUint32(lenValue). + var len = O.length >>> 0; + + // 4. Если IsCallable(callback) равен false, выкинем исключение TypeError. + // Смотрите: http://es5.github.com/#x9.11 + if (typeof callback !== 'function') { + throw new TypeError(callback + ' is not a function'); + } + + // 5. Если thisArg присутствует, положим T равным thisArg; иначе положим T равным undefined. + if (arguments.length > 1) { + T = thisArg; + } + + // 6. Положим k равным 0 + k = 0; + + // 7. Пока k < len, будем повторять + while (k < len) { + + var kValue; + + // a. Положим Pk равным ToString(k). + // Это неявное преобразование для левостороннего операнда в операторе in + // b. Положим kPresent равным результату вызова внутреннего метода HasProperty объекта O с аргументом Pk. + // Этот шаг может быть объединён с шагом c + // c. Если kPresent равен true, то + if (k in O) { + + // i. Положим kValue равным результату вызова внутреннего метода Get объекта O с аргументом Pk. + kValue = O[k]; + + // ii. Вызовем внутренний метод Call функции callback с объектом T в качестве значения this и + // списком аргументов, содержащим kValue, k и O. + callback.call(T, kValue, k, O); + } + // d. Увеличим k на 1. + k++; + } + // 8. Вернём undefined. + }; +} +</pre> + +<h2 id="Specifications" name="Specifications">Спецификации</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Спецификация</th> + <th scope="col">Статус</th> + <th scope="col">Комментарии</th> + </tr> + <tr> + <td>{{SpecName('ES5.1', '#sec-15.4.4.18', 'Array.prototype.forEach')}}</td> + <td>{{Spec2('ES5.1')}}</td> + <td>Изначальное определение. Реализована в JavaScript 1.6.</td> + </tr> + <tr> + <td>{{SpecName('ES6', '#sec-array.prototype.foreach', 'Array.prototype.forEach')}}</td> + <td>{{Spec2('ES6')}}</td> + <td></td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-array.prototype.foreach', 'Array.prototype.forEach')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="Совместимость_с_браузерами">Совместимость с браузерами</h2> + +<div> +<div class="hidden">Таблица совместимости на этой странице создается из структурированных данных. Если вы хотите внести свой вклад, ознакомьтесь с <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> и отправить нам pull request.</div> + +<p>{{Compat("javascript.builtins.Array.forEach")}}</p> +</div> + +<h2 id="See_also" name="See_also">Смотрите также</h2> + +<ul> + <li>{{jsxref("Array.prototype.find()")}}</li> + <li>{{jsxref("Array.prototype.findIndex()")}}</li> + <li>{{jsxref("Array.prototype.map()")}}</li> + <li>{{jsxref("Array.prototype.every()")}}</li> + <li>{{jsxref("Array.prototype.some()")}}</li> + <li>{{jsxref("Map.prototype.forEach()")}}</li> + <li>{{jsxref("Set.prototype.forEach()")}}</li> +</ul> |