Чтобы убедиться что все на месте выведите первый элемент массива phrases в консоль
Перейти к содержимому

Чтобы убедиться что все на месте выведите первый элемент массива phrases в консоль

Упорядоченные наборы данных

Данная глава знакомит читателя с массивами — коллекциями элементов, упорядоченных по индексу. Глава включает в себя описание массивов и массивоподобных структур, таких как Array и TypedArray .

Array объект

Массив представляется собой упорядоченный набор значений, к которому вы ссылаетесь по имени и индексу. Допустим, у вас есть массив с именем emp, содержащий имена сотрудников и упорядоченный по номеру сотрудников. Следовательно, emp[1] будет представлять собой имя сотрудника номер один, emp[2] — имя сотрудника номер два, и т.д.

Язык JavaScript не содержит явного типа данных «массив». Тем не менее, возможно использовать предопределённый объект Array и его методы для работы с массивами в создаваемых приложениях. Объект Array содержит методы для работы с массивами самыми различными способами, например, есть методы для объединения, переворачивания и сортировки. Объект содержит свойство для определения длины массива, а также свойства для работы с регулярными выражениями.

Создание массива

Следующие выражения создают одинаковые массивы:

var arr = new Array(element0, element1, . , elementN); var arr = Array(element0, element1, . , elementN); var arr = [element0, element1, . , elementN]; 

element0, element1, . elementN — список значений элементов массива. Если значения заданы, то эти значения будут являться элементами массива после его инициализации. Свойство length у массива будет равно количеству аргументов.

Синтаксис с использованием квадратных скобок называется «литерал массива» (array literal) или «инициализатор массива». Такая запись короче, чем другие способы создания массива, и, как правило, более предпочтительна. См. Array literals.

Для создания массива без элементов, но ненулевой длины, возможно использовать одно из следующих выражений:

var arr = new Array(arrayLength); var arr = Array(arrayLength); // Точно такой же эффект var arr = []; arr.length = arrayLength; 

Примечание: в примере выше arrayLength должно иметь числовой тип Number . В противном случае будет создан массив с единственным элементом (указанное значение). Вызванная функция arr.length вернёт значение arrayLength , но на самом деле массив будет содержать пустые элементы (undefined). Использование цикла for. in для обработки значений массива не вернёт ни одного элемента.

Массивы могут быть присвоены свойству нового или уже существующего объекта, как показано ниже:

var obj = >; // . obj.prop = [element0, element1, . , elementN]; // OR var obj = prop: [element0, element1, . ., elementN]> 

Если вы хотите инициализировать массив одним элементом и этим элементом является число типа Number, то вы должны использовать квадратные скобки. Если вы создаёте массив с помощью Array (конструктора или функции), а единственным элементом этого массива будет число типа Number, то число это интерпретируется как длина массива (arrayLength), а не как элемент типа Number.

var arr = [42]; // Создаёт массив с одним элементом var arr = Array(42); // Создаёт массив без элементов, // но устанавливает длину массива arr.length в 42 // Это эквивалентно следующему var arr = []; arr.length = 42; 

Вызов Array(N) выбросит RangeError, если N не целое значение, чья дробная часть не ноль. Следующий пример иллюстрирует это.

var arr = Array(9.3); // RangeError: Invalid array length 

Если ваш код нуждается в создании массива с одним элементом произвольного типа данных, то безопасней использовать литеральную запись. Или создайте пустой массив, а затем добавьте необходимый элемент.

Заполнение массива

Вы можете заполнить массив путём присвоения значений его элементам. Для примера:

var emp = []; emp[0] = "Casey Jones"; emp[1] = "Phil Lesh"; emp[2] = "August West"; 

Примечание: Если вы используете нецелое значение в операторе [] обращения к элементу массива, то будет создано соответствующее свойство в объекте, представляющем массив, вместо элемента массива (так как массивы в JavaScript являются объектами).

var arr = []; arr[3.4] = "Oranges"; console.log(arr.length); // 0 console.log(arr.hasOwnProperty(3.4)); // true 

Вы можете заполнить массив во время создания:

var myArray = new Array("Hello", myVar, 3.14159); var myArray = ["Mango", "Apple", "Orange"]; 

Работа с элементами массива

Вы можете ссылаться на элементы массива путём использования их порядковых номеров. Для примера, предположим, что вы определили следующий массив:

var myArray = ["Wind", "Rain", "Fire"]; 

Затем вы сослались на первый элемент массива как myArray[0] и второй элемент массива как myArray[1]. Индексация элементов массива начинается с нуля.

Примечание: оператор обращения к элементу массива (квадратные скобки []) также используется для доступа к свойствам массива (массивы также являются объектами в JavaScript). Например:

var arr = ["one", "two", "three"]; arr[2]; // three arr["length"]; // Вернёт число 3, так как это свойство - длина массива 

Понимание length

На уровне реализации, массивы в JavaScript хранят свои элементы как стандартные свойства объекта, используя индекс в качестве имени свойства. Специальное свойство length всегда возвращает индекс последнего элемента плюс один (в примере ниже, элемент ‘Dusty’ размещается под индексом 30, по этому cats.length возвращает 30 + 1). Особо следует запомнить, что в JavaScript массивы индексируются с нуля: отсчёт ведётся с 0, а не с 1. Из этого и следует, что свойство length всегда на единицу больше, чем наибольший индекс хранящийся в массиве:

var cats = []; cats[30] = ["Dusty"]; console.log(cats.length); // 31 

Также, вы можете задавать значение для length . Установка значения меньшего, чем количество хранящихся в массиве элементов, обрезает массив с конца; установка length равным 0 очищает массив полностью:

var cats = ["Dusty", "Misty", "Twiggy"]; console.log(cats.length); // 3 cats.length = 2; console.log(cats); // выводит в консоль "Dusty,Misty" - элемент "Twiggy" был удалён cats.length = 0; console.log(cats); // выводит пустую строку; массив cats пуст cats.length = 3; console.log(cats); // выводит [undefined, undefined, undefined] 

Перебор содержимого массивов

Очень распространённая задача — это перебор всех элементов массива и обработка каждого элемента некоторой операцией. Вот наипростейший способ сделать это:

var colors = ["red", "green", "blue"]; for (var i = 0; i  colors.length; i++)  console.log(colors[i]); > 

Если вам заранее известно, что ни один элемент массива не будет расценён как false при приведении к boolean — например, каждый элемент массива является DOM (en-US) узлом, тогда вы можете блеснуть чуть более эффективным оборотом:

var divs = document.getElementsByTagName("div"); for (var i = 0, div; (div = divs[i]); i++)  /* Обработать div некоторой операцией */ > 

Подход в примере выше, позволяет избежать проверки длинны массива при каждой итерации, и лишь убеждается, что переменной div присвоен существующий текущий элемент массива при каждом прохождении цикла.

Метод forEach() предоставляет другой способ перебора элементов:

var colors = ["red", "green", "blue"]; colors.forEach(function (color)  console.log(color); >); 

Как вариант, вы можете сократить код программы, используя стрелочные функции из ES6:

var colors = ["red", "green", "blue"]; colors.forEach((color) => console.log(color)); // red // green // blue 

Функция, переданная в метод forEach , будет выполнена по одному разу для каждого элемента массива, при этом сам элемент массива будет передан как аргумент в эту функцию. Элементы, значения которым не присвоены, не обрабатываются forEach циклом.

Заметьте, что элементы, пропущенные при создании массива не обрабатываются методом forEach , однако, undefined элемент обрабатывается в том случае, когда он присвоен ячейке массива вручную:

var array = ["first", "second", , "fourth"]; array.forEach(function (element)  console.log(element); >); // first // second // fourth if (array[2] === undefined)  console.log("array[2] is undefined"); // true > array = ["first", "second", undefined, "fourth"]; array.forEach(function (element)  console.log(element); >); // first // second // undefined // fourth 

Так как в JavaScript элементы массива хранятся как обычные свойства объекта, использование for. in циклов для перебора элементов массива нежелательно, потому что будут обработаны не только элементы массива, но и все перечисляемые свойства массива.

Методы Array

Объект Array имеет следующие методы:

concat() объединяет два массива и возвращает новый массив.

var myArray = new Array("1", "2", "3"); myArray = myArray.concat("a", "b", "c"); // myArray = ["1", "2", "3", "a", "b", "c"]

join(deliminator = ‘,’) объединяет элементы массива в текстовую строку.

var myArray = new Array("Wind", "Rain", "Fire"); var list = myArray.join(" - "); // list = "Wind - Rain - Fire"

push() добавляет один или несколько элементов в конец массива и возвращает результирующую длину.

var myArray = new Array("1", "2"); myArray.push("3"); // myArray =["1", "2", "3"]

pop() удаляет из массива последний элемент и возвращает его.

var myArray = new Array("1", "2", "3"); var last = myArray.pop(); // myArray =["1", "2"], last = "3"

shift() удаляет из массива первый элемент и возвращает его.

var myArray = new Array ("1", "2", "3"); var first = myArray.shift(); // myArray = ["2", "3"], first = "1"

unshift() добавляет один или несколько элементов в начало массива и возвращает его новую длину.

var myArray = new Array("1", "2", "3"); myArray.unshift("4", "5"); // myArray becomes ["4", "5", "1", "2", "3"] 

slice(start_index, upto_index) возвращает секцию массива как новый массив.

var myArray = new Array("a", "b", "c", "d", "e"); myArray = myArray.slice(1, 4); // начиная с индекса 1 извлекаются элементы вплоть до индекса 3 // myArray = [ "b", "c", "d"] 

splice(index, count_to_remove, addElement1, addElement2, . ) удаляет часть элементов из массива и (опционально) заменяет их. Возвращает удалённые элементы.

var myArray = new Array("1", "2", "3", "4", "5"); myArray.splice(1, 3, "a", "b", "c", "d"); // myArray = ["1", "a", "b", "c", "d", "5"] // Этот код, начиная с ячейки под индексом 1 (в которой находилось значение "2"), // удаляет 3 элемента, и вставляет на их место // элементы, переданные в качестве последующих параметров. 

reverse() переставляет элементы массива в обратном порядке: первый элемент становится последним, а последний — первым.

var myArray = new Array("1", "2", "3"); myArray.reverse(); // элементы переставлены myArray = [ "3", "2", "1" ] 

sort() сортирует элементы массива.

var myArray = new Array("Wind", "Rain", "Fire"); myArray.sort(); // массив отсортирован myArray = [ "Fire", "Rain", "Wind" ] 

Метод sort() может принимать в качестве аргумента callback -функцию, которая определяет каким образом сравнивать элементы массива при сортировке. Функция сравнивает два значения, и возвращает одно из трёх значений (список вариантов значений смотрите после примера):

Пример. Следующий код сортирует массив по последнему символу в строке:

var sortFn = function (a, b)  if (a[a.length - 1]  b[b.length - 1]) return -1; if (a[a.length - 1] > b[b.length - 1]) return 1; if (a[a.length - 1] == b[b.length - 1]) return 0; >; myArray.sort(sortFn); // массив отсортирован myArray = ["Wind","Fire","Rain"] 
  • если a меньше чем b в выбранной системе сравнения, возвращаем -1 (или любое отрицательное число)
  • если a больше чем b в выбранной системе сравнения, возвращаем 1 (или любое положительное число)
  • если a и b считаются равными, возвращаем 0.

indexOf(searchElement[, fromIndex]) ищет в массиве элемент со значением searchElement и возвращает индекс первого совпадения.

var a = ["a", "b", "a", "b", "a"]; console.log(a.indexOf("b")); // выводит 1 // Попробуем ещё раз, начиная с индекса последнего совпадения console.log(a.indexOf("b", 2)); // выводит 3 console.log(a.indexOf("z")); // выводит -1, потому что 'z' не найдено 

lastIndexOf(searchElement[, fromIndex]) тоже самое, что и indexOf , но поиск ведётся в обратном порядке, с конца массива.

var a = ["a", "b", "c", "d", "a", "b"]; console.log(a.lastIndexOf("b")); // выводит 5 // Попробуем ещё раз, начиная с индекса, предшествующего индексу последнего совпадения console.log(a.lastIndexOf("b", 4)); // выводит 1 console.log(a.lastIndexOf("z")); // выводит -1 

forEach(callback[, thisObject]) выполняет callback -функцию по каждому элементу массива.

var a = ["a", "b", "c"]; a.forEach(function (element)  console.log(element); >); // выводит в консоль каждый элемент массива по порядку 

map(callback[, thisObject]) возвращает новый массив, содержащий результаты вызова callback -функции для каждого элемента исходного массива.

var a1 = ["a", "b", "c"]; var a2 = a1.map(function (item)  return item.toUpperCase(); >); console.log(a2); // выводит A,B,C 

filter(callback[, thisObject]) возвращает новый массив, содержащий только те элементы исходного массива, для которых вызов callback -функции вернул true.

var a1 = ["a", 10, "b", 20, "c", 30]; var a2 = a1.filter(function (item)  return typeof item == "number"; >); console.log(a2); // выводит 10,20,30 

every(callback[, thisObject]) возвращает true, если вызов callback -функции вернул true для всех элементов массива.

function isNumber(value)  return typeof value == "number"; > var a1 = [1, 2, 3]; console.log(a1.every(isNumber)); // выводит true var a2 = [1, "2", 3]; console.log(a2.every(isNumber)); // выводит false 

some(callback[, thisObject]) возвращает true, если вызов callback -функции вернёт true хотя бы для одного элемента.

function isNumber(value)  return typeof value == "number"; > var a1 = [1, 2, 3]; console.log(a1.some(isNumber)); // выводит true var a2 = [1, "2", 3]; console.log(a2.some(isNumber)); // выводит true var a3 = ["1", "2", "3"]; console.log(a3.some(isNumber)); // выводит false 

Те из методов выше, что принимают callback -функцию в качестве аргумента, известны как методы итерации (iterative methods), потому что определённым образом проходятся по всем элементам массива. Каждый из таких методов принимает второй, опциональный элемент, называемый thisObject . Если этот аргумент присутствует, то его значение присваивается ключевому слову this в теле callback -функции. Иначе, как и в любом другом случае вызова функции вне явного контекста, this будет ссылаться на глобальный объект ( window ).

В действительности callback -функция вызывается с тремя аргументами. Первый аргумент — текущий элемент массива, второй — индекс этого элемента, и третий — ссылка на сам массив. Однако, в JavaScript, функции игнорируют любые аргументы, которые не перечислены в списке аргументов. Таким образом, нет ничего страшного в использовании функции с одним аргументом, такой как alert .

reduce(callback[, initialValue]) последовательно применяет callback -функцию callback(firstValue, secondValue) для того, чтобы свести все элементы массива к одному значению. В первый параметр функции передаётся предыдущий результат работы функции или первый элемент, а во второй — текущий элемент. Третьим параметром передаётся индекс текущего элемента.

var a = [10, 20, 30]; var total = a.reduce(function (first, second, index)  return first + second; >, 0); console.log(total); // выводит 60 

reduceRight(callback[, initalvalue]) работает так же как и reduce() , но порядок обхода ведётся от конца к началу.

Методы reduce и reduceRight являются наименее очевидными методами объекта Array. Они должны использоваться в алгоритмах, которые рекурсивно совмещают два элемента массива, для сведения всей последовательности к одному значению.

Многомерные массивы

Массивы могут быть вложенными, то есть массив может содержать массивы в элементах. Используя эту возможность массивов JavaScript, можно построить многомерные массивы.

Следующий код создаёт двумерный массив:

var a = new Array(4); for (i = 0; i  4; i++)  a[i] = new Array(4); for (j = 0; j  4; j++)  a[i][j] = "[" + i + "," + j + "]"; > > 

В этом примере создаётся массив со следующим содержимым:

Ряд 0: [0,0] [0,1] [0,2] [0,3] Ряд 1: [1,0] [1,1] [1,2] [1,3] Ряд 2: [2,0] [2,1] [2,2] [2,3] Ряд 3: [3,0] [3,1] [3,2] [3,3]

Массивы и регулярные выражения

Когда массив является результатом вычислений регулярного выражения над строкой, он содержит свойства и элементы с информацией о совпадениях. Массив возвращается функциями RegExp.exec() , String.match() и String.split() Подробнее о том, как использовать массивы с регулярными выражениями смотрите в Regular Expressions.

Работа с массивоподобными объектами

Некоторые объекты в JavaScript, такие как NodeList , возвращаемые методом document.getElementsByTagName() , или специальный объект arguments , доступный внутри функции, выглядят и ведут себя как обычные массивы, однако не имеет всех присущих массиву методов. Так например, объект arguments имеет свойство length , но не имеет метода forEach() .

Методы из прототипа Array, могут быть вызваны для массивоподобных объектов. Например:

function printArguments() < Array.prototype.forEach.call(arguments, function(item) < console.log(item); >); >

Также методы из прототипа Array могут быть применены и к строкам, потому как строки предоставляют доступ к своим символам сходным образом:

Array.prototype.forEach.call("a string", function (chr)  console.log(chr); >); 

Типизированные массивы

JavaScript typed arrays (типизированные массивы) являются массивоподобными объектами, которые предоставляют механизм доступа к сырым бинарным данным. Как вы уже знаете, Array массивы динамически растут, сокращаются и могут содержать значения любых типов JavaScript. Движки JavaScript производят оптимизации, благодаря чему, эти операции происходят быстро. Однако, веб приложения становятся все более мощными, добавляются возможности манипуляции со звуковыми и видеоданными, доступ к сырым данным WebSockets, и тому подобное. Становится очевидным, что возможность быстрой и эффективной работы с двоичными данными в JavaScript будет очень полезной. Для чего типизированные массивы и предназначены.

Буферы и представления: архитектура типизированных массивов

Для достижения максимальной гибкости и производительности, реализация типизированных массивов в JavaScript разделена на буферы и представления. Буфер ( ArrayBuffer ) это объект, представляющий из себя блок данных; он не имеет формата и не предоставляет возможности доступа к своему содержимому. Для доступа к памяти буфера вам нужно использовать представление. Представление являет собой контекст, имеющий тип данных, начальную позицию в буфере, и количество элементов — это позволяет представить данные в виде актуального типизированного массива.

Typed arrays in an ArrayBuffer

ArrayBuffer

Объект ArrayBuffer это стандартный набор бинарных данных с фиксированной длиной. Вы не можете манипулировать содержимым ArrayBuffer напрямую. Вместо этого необходимо создать типизированное представление DataView , которое будет отображать буфер в определённом формате, и даст доступ на запись и чтение его содержимого.

Типизированные представления

Название типизированного представления массива говорит само за себя. Оно представляет массив в распространённых числовых форматах, таких как Int8 , Uint32 , Float64 и так далее. Среди прочих существует специальное представление Uint8ClampedArray . Оно ограничивает значения интервалом от 0 до 255. Это полезно, например, при Обработке данных изображения в Canvas.

Type Value Range Size in bytes Web IDL type
Int8Array -128 to 127 1 byte
Uint8Array 0 to 255 1 octet
Uint8ClampedArray 0 to 255 1 octet
Int16Array -32768 to 32767 2 short
Uint16Array 0 to 65535 2 unsigned short
Int32Array -2147483648 to 2147483647 4 long
Uint32Array 0 to 4294967295 4 unsigned long
Float32Array -3.4e38 to 3.4e38 4 unrestricted float
Float64Array -1.8e308 to 1.8e308 8 unrestricted double
BigInt64Array -2 63 to 2 63 — 1 8 bigint
BigUint64Array 0 to 2 64 — 1 8 bigint

Для получения подробных сведений смотрите Типизированные массивы JavaScript и справочную документацию для TypedArray .

  • « Предыдущая статья
  • Следующая статья »

Found a content problem with this page?

  • Edit the page on GitHub.
  • Report the content issue.
  • View the source on GitHub.

This page was last modified on 7 авг. 2023 г. by MDN contributors.

Your blueprint for a better internet.

Цикл for для массивов в JavaScript

Массивы также можно перебирать циклом for . Давайте посмотрим, как это делается. Пусть у нас дан вот такой массив:

let arr = [1, 2, 3, 4, 5];

Выведем элементы этого массива в цикле:

for (let i = 0; i

Можно не отнимать от длины массива единицу, а использовать нестрогое сравнение:

for (let i = 0; i < arr.length; i++) < console.log(arr[i]); >

Перебор массива циклом for дает больший контроль за происходящим. К примеру, можно вывести элементы не с нулевого, а с первого:

for (let i = 1; i < arr.length; i++) < console.log(arr[i]); >

Можно вывести элементы в обратном порядке:

for (let i = arr.length — 1; i >= 0; i—) < console.log(arr[i]); >

Выведите в консоль все элементы следующего массива:

let arr = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’];

Выведите в консоль все элементы следующего массива, за исключением нулевого и последнего:

let arr = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’];

Выведите в консоль элементы следующего массива в обратном порядке:

let arr = [‘a’, ‘b’, ‘c’, ‘d’, ‘e’];

Исправьте ошибку, допущенную в следующем коде:

Перебирающие методы массивов изнутри

Методы массивов forEach , map , filter , some , every и reduce являются неотъемлимой частью функционального программирования на JavaScript. В этой статье подробно рассмотрим применение каждого из них, а также их реализацию в виде функций.

forEach

Самый простой способ разобраться, как работают функции высшего порядка, принимающие callback’и, — самостоятельно переписать несколько нативных методов. Начнём с самого простого метода Array.prototype.forEach . Метод массивов forEach принимает два аргумента: первый (обязательный) — callback функция, которая будет выполнена для каждого элемента массива один раз и второй (необязательный) — значение, которое будет использовано в качестве this при вызове функции callback . Работает это следующим образом:

['JavaScript', 'is', 'awesome'].forEach(function(item, index, arr)  console.log(item, index, arr); >); // Выведет в консоль // JavaScript 0 ["JavaScript","is","awesome"] // is 1 ["JavaScript","is","awesome"] // awesome 2 ["JavaScript","is","awesome"]

В callback функцию передаётся три аргумента: item , соответствующий элементу массива, index , равный номеру элемента в массиве, и arr — ссылка на массив. Таким образом, справедливо следующее выражение arr[index] === item . Аргументам передаваемым в callback функцию можно давать разные названия в зависимости от контекста выполнения — выполнение callback функции от этого не изменится:

[1, 2, 3, 4, 5].forEach(function(num, i, nums)  console.log(num * 2); // 2 4 6 8 10 >);

Как я писал выше, помимо callback функции метод forEach принимает ещё один аргумент — значение, которое будет использовано в качестве this при вызове функции callback . Зачем это может понадобиться? По умолчанию this не определён, то есть равен undefined . В некоторых ситуациях, особенно при работе с функциями конструкторами, необходимо задать контекст выполнения callback функции:

var Person = function(name)  this.name = name; >; Person.prototype.say = function(phrase)  console.log(this.name + ' says ' + phrase); > Person.prototype.mumble = function(phrases)  phrases.forEach(function(phrase)  this.say(phrase); >); > var johnDoe = new Person('John Doe'); johnDoe.mumble(['Hello, World!', 'JS is great', 'I\'m designer and i don\'t have job']);

Подобный код, на первый взгляд, может оказаться полностью рабочим. Тем не менее, после его выполнения всё, что мы увидим будет ошибка Cannot read property ‘say’ of undefined . Данная ошибка показывает, что при выполнении метода forEach на передаваемом в метод mumble массиве phrases не задаётся контекст испольнения callback функции. Проще говоря, callback функция пытается выполнить подобный код undefined[say](words) . Решается данная проблема элементарно — передётся второй аргумент в метод forEach , который и указывает ему, что брать за this :

// . Person.prototype.mumble = function(arr)  arr.forEach(function(words) this.say(words); >, this); > var johnDoe = new Person('John Doe'); johnDoe.mumble(['Hello, World!', 'JS is great', 'I\'m designer and i don\'t have job']); // Выведет в консоль // John Doe says Hello, World! // John Doe says JS is great // John Doe says I'm designer and i don't have job
forEach своими руками

Теперь, когда вы знаете, как работает forEach , настало время написать функцию, которая делает всё тоже самое. При создании функции each будем руководствоваться тремя правилами:

  1. Функция принимает три аргумента: массив, по которому будет происходить итерация, callback фунцию, которая будет выполнена для каждого элемента массива, и значение, которое будет использовано callback функцией в качестве this .
  2. callback функция, в свою очередь, также работает с тремя аргументами: текущий элемент массива, индекс элемента, ссылка на сам массив.
  3. Функция ничего не возвращает.

Самое очевидное решение: используя цикл for перебрать каждый элемент массива и выполнить передаваемую callback функцию с каждым. Сделать это очень просто:

var each = function(arr, callback, thisArg)  var i, length = arr.length; for (i = 0; i  length; i = i + 1)  callback(arr[i], i, arr); > >;

Функция each будет отлично работать, за исключением того, что не соблюдается часть первого правила — для callback функции нельзя задать контекст, то есть нельзя присвоить значение this :

each([1, 2, 3], function(num, i, nums)  console.log('Number: ' + num + ', index: ' + i + ',', nums) >); // Выведет в консоль // Number: 1, index: 0, [1,2,3] // Number: 2, index: 1, [1,2,3] // Number: 3, index: 2, [1,2,3]

Чтобы можно было осуществлять передачу ключевого слова this в функцию each достаточно воспользоваться методом функций call , который позволяет вызвать функцию и явно указать, на что будет указывать ключевое слово this .

var each = function(arr, callback, thisArg)  var i, length = arr.length; for (i = 0; i  length; i = i + 1)  callback.call(thisArg, arr[i], i, arr); > >;

Теперь функция each работает с массивами в точности так, как и метод forEach . Чтобы её протестировать, можно запустить её вместе с кодом из предыдущего примера.

var Person = function(name)  this.name = name; >; Person.prototype.say = function(phrase)  console.log(this.name + ' says ' + phrase); > Person.prototype.mumble = function(phrases)  each(phrases, function(phrase)  this.say(phrase); >, this); > var johnDoe = new Person('John Doe'); johnDoe.mumble(['Hello, World!', 'JS is great', 'I\'m designer and i don\'t have job']); // Выведет в консоль // John Doe says Hello, World! // John Doe says JS is great // John Doe says I'm designer and i don't have job

Несмотря на кажущуюся одинаковость метода forEach и написанной нами выше функции each , между ними есть одно очень важное различие: метод forEach работает только с массивами, в то время как функция each может также успешно работать с любыми коллекциями.

Скорее всего, вы уже видели ранее подобную конструкцию, которую используют многие JavaScript разработчики для итерации по всем элементам из DOM коллекции:

var links = document.links; // коллекция всех ссылок на странице [].forEach.call(links, function(link)  // Добавление класса link-active для всех ссылок на странице link.classList.add('link-active'); >);

Подобная конструкция может ввести в замешательство практически любого программиста, который раньше не использовал её сам. Подробное объяснение, как именно она работает можно найти в этом вопросе на Stackoverflow. Нужна она лишь для того, чтобы провести итерацию по всем элементам выбранной DOM коллекции и выполнить callback функцию для каждого из них. При использовании написанной нами функции each надобности в такой хитрой конструкции нет, так как она поддерживает работу не только с массивами, но и с любыми коллекциями, в том числе и коллекциями DOM элементов:

var links = document.links; // коллекция всех ссылок на странице each(links, function(link)  // Добавление класса link-active для всех ссылок на странице link.classList.add('link-active'); >);

Когда появится широкая поддежка ES6 метод forEach можно будет использовать с DOM коллекциями более простым способом с помощью оператора Spread:

[. links].forEach(function(link)  link.classList.add('link-active'); >);
map

Метод массивов map похож по своей функциональности на forEach , но результат выполнения callback функции добавляется в новый массив, который возвращается после последней итерации. Другими словами, результатом метода map всегда является новый массив с результатами выполнения функции callback на исходном массиве.

var nums = [10, 20, 30, 40]; var results = nums.map(function(num, index, arr)  // Возведение числа в степень соответсвующую его индексу в массиве return Math.pow(num, index); >); // Исходный массив nums не изменяется console.log(nums); // [10,20,30,40] // результат выполнения map, записанный в переменную console.log(results); // [1,20,900,64000]

Также, как и в случае с forEach map помимо callback функции принимает второй параметр, который позволяет задать контекст и явно указать this :

var Person = function(name)  this.name = name; this.phrases = null; >; Person.prototype.say = function(phrase)  return this.name + ' says ' + phrase; > Person.prototype.grabPhrases = function(phrases)  this.phrases = phrases.map(function(phrase) // Добавление изменённой строки в новый массив return this.say(phrase); >, this) > var johnDoe = new Person('John Doe'); johnDoe.grabPhrases(['Hello, World!', 'JS is great', 'I\'m designer and i don\'t have job']); console.log(johnDoe.phrases); // ["John Doe says Hello, World!","John Doe says JS is great","John Doe says I'm designer and i don't have job"]

Как вы могли заметить, при использовании map и forEach всегда использовалась анонимная функция в качестве callback . Это совсем не обязательно. Вы можете объвить функцию, которую хотите использовать в качестве callback заранее, а затем просто передать её в качестве параметра.

var slice = function(str)  // вернуть первые пять символов из строки return str.slice(0, 5); >; var frameworks = ['Knockout', 'Backbone', 'Angular'].map(slice); console.log(frameworks); // ["Knock","Backb","Angul"]

В некоторых ситуациях можно вообще не создавать отдельную функцию и пользоваться нативными методами. Пример выше, в котором каждое число в массиве возводилось в степень, соответствующую своему индексу, можно значительно сократить:

// Длинный вариант с ненужной анонимной функцией var nums = [10, 20, 30, 40]; var results = nums.map(function(num, index, arr)  return Math.pow(num, index); >); // Короткий вариант, ничего лишнего var nums = [10, 20, 30, 40]; var results = nums.map(Math.pow);

Передвая callback функцию подобным образом вы не теряете возможность явно указать this . Таким образом, метод grabPhrases из функции конструктора Person также можно немного сократить:

Person.prototype.grabPhrases = function(phrases)  // Ненужная анонимная функция this.phrases = phrases.map(function(phrase)  return this.say(phrase); >, this); > // Выполнение функции this.say для каждого элемента массива Person.prototype.grabPhrases = function(phrases)  this.phrases = phrases.map(this.say, this) >

В отличие от forEach при использовании map вам становится доступен chaining. Это значит, что вы можете последовательно применить метод на возвращенный после map массив.

// Получение квадратного корня из чисел с помощью map // и вывод результатов в консоль с помощью forEach [1, 4, 9, 16].map(Math.sqrt).forEach(function(num)  console.log(num); // 1 2 3 4 >);
map своими руками

Как и при создании аналога forEach напишем небольшие правила, которыми будем руководствоваться при создании функции map :

  1. Функция возвращает новый массив, оставляя исходный без изменений.
  2. Всё, что возвращает callback функция добавляется в новый массив.
  3. Функция принимает три аргумента: массив, по которому будет происходить итерация, callback фунцию, которая будет выполнена для каждого элемента массива, и значение, которое будет использовано callback функцией в качестве this .
  4. callback функция, в свою очередь, также работает с тремя аргументами: текущий элемент массива, индекс элемента, ссылка на сам массив.

Правил стало больше, но последними двумя мы уже пользовались при создании функции each , а, значит, вы уже знаете, как с ними справиться.

var map = function(arr, callback, thisArg)  var i, length = arr.length, results = []; for (i = 0; i  length; i = i + 1)  results.push(callback.call(thisArg, arr[i], i, arr)); > return results; >;

Менять исходный массив нельзя, поэтому нужно создать новый массив в самом начале выполнения функции map . Назовём его results . В созданный нами массив results при кажом выполнении будем добавлять результат выполнения функции callback с помощью метода push . После завершения последней итерации всё, что остаётся сделать — вернуть массив results .

Написанная нами функция map работает точно так же, как и метод массивов map , но, как и each , может принимать в качестве аргументов любый другие коллекции.

var pows = map([10, 20, 30], Math.pow); var frameworks = map(['Knockout', 'Backbone', 'Angular'], function(framework)  return framework.slice(0, 5); >); console.log(pows); // [1,20,900] console.log(frameworks); // ["Knock","Backb","Angul"]

Небольшой совет: не используйте метод map для манипуляций с коллекциями DOM элементов, например, чтобы добавить класс всем элементам коллекции.

[].map.call(document.links, function(link)  link.classList.add('link'); >);

Данный код сработает и всем ссылкам будет добавлен класс link , но пимимо этого будет создан дополнительный пустой массив, что скажется на производительности при большом объеме итерируемой коллекции. В подобных случаях следует использовать исключительно forEach .

Тем не менее, map отлично подходит для получения данных из DOM коллекций. Например, получение всех href атрибутов будет выглядеть следующим образом:

var hrefs = [].map.call(document.links, function(link)  return link.href; >); console.log(hrefs); // ["http://google.ru", "http://jsraccoon.ru" . ]
filter

Метод filter , как и следует из названия, служит для фильтрации массива по правилам, заданным в callback функции. Так же, как в случае с map создаётся новый массив, куда добавляются все элементы прошедшие провеку колбэком.

var moreThanFive = [1, 20, 4, 2, 5, 3, 24, 6, 45].filter(function(num)  return num > 5; >); console.log(moreThanFive); // [20,24,6,45]

При использовании метода filter результатом выполнения может быть любое значение, но данные из исходного массива будут добавлены только в том случае, если значение является правдивым. Напомню, что правдивыми значениями являются все, кроме:

  1. пустой строки »
  2. числа ноль 0
  3. false
  4. undefined
  5. null

Тем не менее, пользоваться подобным способом фильтрации массива не стоит в силу его неочевидности. Поэтому рекомендуется создавать callback функцию таким образом, чтобы она всегда возвращала либо true , либо false .

Немного более сложный пример использования метода filter . Допустим, что мы получаем JSON файл с сервера с подобным содержимым:

["id":1,"name":"Ernest","email":"ebishop0@myspace.com","isCustomer":false>, "id":2,"name":"Michael","email":"mturner1@multiply.com","isCustomer":false>, "id":3,"name":"Mildred","email":"mwelch2@google.it","isCustomer":false>, "id":4,"name":"Jeremy","email":"jwilson3@hostgator.com","isCustomer":false>, "id":5,"name":"Judy","email":"jellis4@ameblo.jp","isCustomer":true>, "id":6,"name":"Judy","email":"jrogers5@ow.ly","isCustomer":false>, "id":7,"name":"Chris","email":"cbennett6@nasa.gov","isCustomer":false>, "id":8,"name":"Ruth","email":"rmason7@simplemachines.org","isCustomer":true>, "id":9,"name":"Justin","email":"jmedina8@indiegogo.com","isCustomer":true>, "id":10,"name":"Dennis","email":"dflores9@g.co","isCustomer":true>]

После получения данных (с помощью AJAX или JSONP, например) мы хотим их отфильтровать, узнав из свойства isCustomer , является ли данных человек нашим клиентом или нет. Вот здесь и пригодится метод filter :

// . // Получили данные с сервера и записали их в переменную data var customers = data.filter(function(person)  return person.isCustomer; >); console.log(customers); // [, // , // , // ]

Или же можно руководствоваться немного другим, более сложным принципом при выборе цели. Например, мы решили, что если email клиента не начинается с буквы j , то он определённо нам не подходит.

// . // Получили данные с сервера и записали их в переменную data var customers = data.filter(function(person)  return person.email.charAt(0).toLowerCase() === 'j'; >); console.log(customers); // [, // , // , // ]
filter своими руками

Как и для прошлых функций map и forEach напишем небольшой свод правил:

  1. Функция возвращает новый массив, оставляя исходный без изменений.
  2. Данные исходного массива передаются в callback функцию. Результат выполнения callback функции решает будет ли добавлен данный элемент в новый массив.
  3. Функция принимает три аргумента: массив, по которому будет происходить итерация, callback фунцию, которая будет выполнена для каждого элемента массива, и значение, которое будет использовано callback функцией в качестве this .
  4. callback функция, в свою очередь, также работает с тремя аргументами: текущий элемент массива, индекс элемента, ссылка на сам массив.
var filter = function(arr, callback, thisArg)  var i, length = arr.length, results = []; for (i = 0; i  length; i = i + 1)  if (callback.call(thisArg, arr[i], i, arr))  results.push(arr[i]); > > return results; >;

С помощью всё того же метода функций call мы вызываем callback функцию, но на этот раз всё, что нас будет интересовать — вернула ли функция правдивое значение. Если результат содержит правдивое значение, то данные будут добавлены в массив, если же нет, то просто проигнорированы.

Удостоверимся, что функция filter работает, как мы её и задумывали:

var strs = ['Hello', ',', 'JavaScript', 'World', '!']; var data = filter(strs, function(str)  return str.toLowerCase() !== str; >); console.log(data); // ["Hello","JavaScript","World"]

Небольшой хак: чтобы отфильтровать все ложные значения из массива можно воспользоваться конструктором Boolean :

var data = [32, '', null, 'JavaScript', undefined, 0]; var trueData = data.filter(Boolean); console.log(trueData); // [32,"JavaScript"]
some и every

Методы some и every во многом похожи друг на друга. Оба метода возвращают true или false . some возвращает true тогда, когда хотя бы один элемент массива отвечает переданным в callback функцию условиям. every вернёт true , когда все элементы массива отвечают данным условиям. Звучит грозно, но, на самом деле всё очень просто.

var fives = [5, 5, 5, 6, 5, 5]; var result = fives.every(function(five)  return five === 5; >); console.log(result); // false — в массиве же есть шестёрка var fives = [5, 5, 5, 5, 5, 5]; var result = fives.every(function(five)  return five === 5; >); console.log(result); // true — теперь там только пятёрки, всё хорошо var nums = [1, 2, 3, 4, 5]; var result = nums.some(function(num)  return num > 3; >); console.log(result); // true — в массиве есть хотя бы одно значение больше 3 var nums = [10, 20, 30, 40, 50]; var result = nums.some(function(num)  return num  5; >); console.log(result); // false — в массиве нет ни одного значения меньше 5

Методы some и every очень удобно использовать вместе с методом filter для вложенных массивов. Чтобы понять, как это работает, опять представим, что мы получили данные с сервера в виде JSON файла, который содержит массив объектов (наших покупателей). У каждого покупателя есть свойство purchases , которое представляет собой список приобретённых покупателем товаров в нашем магазине ранее.

["name":"Wanda","email":"wjenkins0@irs.gov","purchases":['iPhone', 'dishwasher', 'cucumbers']>, "name":"Nicholas","email":"nkennedy1@ox.ac.uk","purchases":['tomatoes', 'toster', 'grill']>, "name":"Paula","email":"pstephens2@boston.com","purchases":['apples', 'Macbook', 'iPhone']>, "name":"Fred","email":"fpeterson3@reuters.com","purchases":['beef', 'pork', 'cheese']>, "name":"Andrew","email":"awagner4@weebly.com","purchases":['cottage cheese', 'cream', 'candies']>, "name":"Steven","email":"sgonzales5@mashable.com","purchases":['iMac', 'Android phone', 'Windows 10']>, "name":"Harry","email":"hallen6@nasa.gov","purchases":['green grape', 'tomatoes', 'potatoes']>, "name":"Bonnie","email":"breyes7@kickstarter.com","purchases":['Windows 10', 'dishwasher', 'grill']>, "name":"Lisa","email":"lgreene8@spotify.com","purchases":['pork', 'iMac', 'cheese']>, "name":"Wayne","email":"wramos9@yahoo.com","purchases":['apples', 'cream', 'candies']>]

Чтобы понять, какие клиенты нам принесли больше всего прибыли, мы хотим их отфильтровать и посмотреть, кто из них покупал у нас технику от Apple (iPhone, Macbook или iMac). Метод some поможет сделать это с помощью всего нескольких строк кода.

// . // Получили данные с сервера и записали их в переменную data var customers = data.filter(function(customer)  return customer.purchases.some(function(purchase)  return purchase === 'iPhone' || purchase === 'Macbook' || purchase === 'iMac'; >); >); console.log(customers); // [, // , // <"name":"Steven","email":"sgonzales5@mashable.com","purchases":["iMac","Android phone","Windows 10"]>, // ]
some и every своими руками
  1. Функция возвращает только true или false
  2. Каждое значение передаётся в callback функцию и на результате её выполнения для всех элементов массива решается, какой будет результат.
  3. Функция принимает три аргумента: массив, по которому будет происходить итерация, callback фунцию, которая будет выполнена для каждого элемента массива, и значение, которое будет использовано callback функцией в качестве this .
  4. callback функция, в свою очередь, также работает с тремя аргументами: текущий элемент массива, индекс элемента, ссылка на сам массив.
var some = function(arr, callback, thisArg)  var i, length = arr.length; for (i = 0; i  length; i = i + 1)  if (callback.call(thisArg, arr[i], i, arr))  return true; > > return false; >;

Функция some при каждой итерации проверяет, является ли результат выполнения callback функции правдивым. Если она находит хотя бы один правдивый результат, то прерывает своё выполнение и сразу возвращает true .

var every = function(arr, callback, thisArg)  var i, length = arr.length; for (i = 0; i  length; i = i + 1)  if (!callback.call(thisArg, arr[i], i, arr))  return false; > > return true; >;

Функция every построена по противоположному принципу. Если хотя бы одно значение не является верным, то сразу же возвращается false без дальнейшего перебирания массива.

Функции every и some работают идентично соответствующим им методам и будут давать одинаковые резутаты. Тем не менее, написанные нами функции работают лучше нативных методов. Почему? Используя методы массивов some и every вы подразумеваете, что callback функция будет выполнена для всех элементов без исключения. Но, может оказаться так, что первый элемент в массиве уже содержит нужные нам данные и итерация по всем остальным будет абсолютно бесполезной. В написанных нами функциях таких итераций не будет — когда будет найдено искомое значение функция сразу же прекратит своё выполнение. Подобный подход может дать достаточно ощутимый прирост производительности при работе с большими объемами данных, например, с JSON файлами содержащими несколько тысяч объектов.

reduce

callback функция всех рассмотренных выше методов массивов работает с одинаковым набором данных: значением, индексом и массивом. Метод reduce не такой, как все. Принцип его работы немного отличается от всех остальных методов. Начнём сразу с примера:

var nums = [10, 20, 30, 40, 50]; var sum = nums.reduce(function(result, num)  return result + num; >, 0); console.log(sum); // 150 сумма всех элементов массива

Метод reduce принимает два аргумента callback функцию и начальное значение, которое будет присвоено аргументу result в примере выше при первой итерации. callback функция принимает целых 4 аргумента: промежуточное значение (аргумент result в примере выше), элемент массива, индекс элемента и сам массив. После каждой итерации в промежуточное значение записываются новые данные, которые берутся из результата выполнения функции callback при прошлой итерации:

var nums = [10, 20, 30, 40, 50]; var sum = nums.reduce(function(result, num)  console.log(result); return result + num; >, 0); // Будет выведено в консоль // 0 начальное значение // 10 начальное значение + первый элемент в массиве = промежуточное значение // 30 промежуточное значение + второй элемент в массиве = промежуточное значение // 60 и так далее // 100

Разумеется, reduce может работать с любыми типами данных, не только с числами. Пример со строками (в данном случае в качестве начального значения стоит передавать пустую строку):

var strs = ['JavaScript', 'is', 'awesome']; var result = strs.reduce(function(phrase, word, index)  // Перед первым словом не надо ставить пробел return (index === 0) ? phrase + word : phrase + ' ' + word; >, ''); console.log(result); // JavaScript is awesome

Пример с многомерным массивом (начинаем с пустого массива):

var arrs = [[1, 2, 3], [4, 5], [6], [7, 8], [9, 10, 11]]; var concat = arrs.reduce(function(result, current)  return result.concat(current); >, []); console.log(concat); // [1,2,3,4,5,6,7,8,9,10,11]
reduce своими руками

Вы уже знаете — у нас есть правила:

  1. Функция принимает три аргумента: массив, callback функцию, начальное значение.
  2. После каждой итерации в промежуточное значение перезаписывается значением, полученным в результате выполнения callback функции. 3. callback функция принимает четыре аргумента: промежуточное значение, текущий элемент массива, индекс элемента, ссылка на сам массив.
  3. Явно указать значение this нельзя.
var reduce = function(arr, callback, startValue)  var i, length = arr.length, result = startValue; for (i = 0; i  length; i = i + 1)  result = callback.call(null, result, arr[i], i, arr); > return result; >;

В нативном методе указывать значение this нельзя, поэтому вместо введения в функцию ещё одного аргумента thisArg мы просто передаём null в вызов функции.

Протестируем написанную нами функцию reduce на предыдущих примерах, чтобы убедиться, что всё работает, как мы и ожидаем.

var arrs = [[1, 2, 3], [4, 5], [6], [7, 8], [9, 10, 11]]; var strs = ['JavaScript', 'is', 'awesome']; var strResults = reduce(strs, function(phrase, word, index)  return (index === 0) ? phrase + word : phrase + ' ' + word; >, ''); var arrResults = reduce(arrs, function(result, current)  return result.concat(current); >, []); console.log(strResults); // JavaScript is awesome console.log(arrResults); // [1,2,3,4,5,6,7,8,9,10,11]

Выводим элемент в консоль

Мы сказали JavaScript найти на странице элемент с классом page , но как узнать, что он его действительно нашёл? И что элемент — тот самый? Для этого нам понадобится консоль.

Консоль — это инструмент разработчика, который помогает тестировать код. Если во время выполнения скрипта возникнет ошибка, в консоли появится сообщение о ней. А ещё в консоль можно выводить текстовые подсказки. В нашем интерфейсе консоль находится справа от редактора кода, между мини-браузером и списком задач. Чтобы увидеть сообщения в консоли, её нужно развернуть, щёлкнув по значку справа.

Задачи Выполнено 0 из 3

Чтобы вывести сообщение в консоль, нужно использовать console.log :

console.log('Привет от JavaScript!');

В результате этой инструкции в консоли появится сообщение Привет от JavaScript!

В консоль можно выводить не только текст, но и результаты выполнения инструкций. Например, найденный с помощью querySelector элемент:

console.log(document.querySelector('.page'));

Инструкция получилась длинной и сложной, но вскоре мы разберём, как её упростить. А пока займёмся тестированием кода. Так называется этап создания программы, когда мы проверяем, что всё работает, как надо. И это не менее важно, чем написание кода.

Давайте убедимся, что JavaScript нашёл нужный элемент, а заодно потренируемся работать с консолью.

Перейти к заданию

  • index.html Сплит-режим
  • style.css Сплит-режим
  • script.js Сплит-режим

FlashNews!

На главную

email

Новая библиотека для создания графиков

Теперь вы можете создать дашборд за считанные секунды.

Что там у роботов?

В робототехнике происходит много интересного, эта новость могла бы быть об этом, но нет.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *