# Массивы: методы В этой главе мы рассмотрим встроенные методы массивов JavaScript. [cut] ## Метод split Ситуация из реальной жизни. Мы пишем сервис отсылки сообщений и посетитель вводит имена тех, кому его отправить: `Маша, Петя, Марина, Василий...`. Но нам-то гораздо удобнее работать с массивом имен, чем с одной строкой. К счастью, есть метод `split(s)`, который позволяет превратить строку в массив, разбив ее по разделителю `s`. В примере ниже таким разделителем является строка из запятой и пробела. ```js //+ run var names = 'Маша, Петя, Марина, Василий'; var arr = names.split(', '); for (var i=0; i
`arr.splice(index[, deleteCount, elem1, ..., elemN])`
Удалить `deleteCount` элементов, начиная с номера `index`, а затем вставить `elem1, ..., elemN` на их место.
Посмотрим примеры. ```js //+ run var arr = ["Я", "изучаю", "JavaScript"]; *!* arr.splice(1, 1); // начиная с позиции 1, удалить 1 элемент */!* alert(arr); // осталось ["Я", "JavaScript"] ``` Ниже продемонстрировано, как использовать `splice` для удаления одного элемента. Следующие за удаленным элементы сдвигаются, чтобы заполнить его место. ```js //+ run var arr = ["Я", "изучаю", "JavaScript"]; *!* arr.splice(0, 1); // удалить 1 элемент, начиная с позиции 0 */!* alert( arr[0] ); // "изучаю" стал первым элементом ``` Следующий пример показывает, как *заменять элементы*: ```js //+ run var arr = [*!*"Я", "сейчас", "изучаю",*/!* "JavaScript"]; // удалить 3 первых элемента и добавить другие вместо них arr.splice(0, 3, "Мы", "изучаем") alert( arr ) // теперь [*!*"Мы", "изучаем"*/!*, "JavaScript"] ``` Метод `splice` возвращает массив из удаленных элементов: ```js //+ run var arr = [*!*"Я", "сейчас",*/!* "изучаю", "JavaScript"]; // удалить 2 первых элемента var removed = arr.splice(0, 2); alert( removed ); // "Я", "сейчас" <-- array of removed elements ``` Метод `splice` также может вставлять элементы без удаления, для этого достаточно установить `deleteCount` в `0`: ```js //+ run var arr = ["Я", "изучаю", "JavaScript"]; // с позиции 2 // удалить 0 // вставить "сложный", "язык" arr.splice(2, 0, "сложный", "язык"); alert(arr); // "Я", "изучаю", "сложный", "язык", "JavaScript" ``` Допускается использование отрицательного номера позиции, которая в этом случае отсчитывается с конца: ```js //+ run var arr = [1, 2, 5] // начиная с позиции индексом -1 (предпоследний элемент) // удалить 0 элементов, // затем вставить числа 3 и 4 arr.splice(-1, 0, 3, 4); alert(arr); // результат: 1,2,3,4,5 ``` ## Метод slice Метод `slice(begin, end)` копирует участок массива от `begin` до `end`, не включая `end`. Исходный массив при этом не меняется. Например: ```js //+ run var arr = ["Почему", "надо", "учить", "JavaScript"]; var arr2 = arr.slice(1,3); // элементы 1, 2 (не включая 3) alert(arr2); // надо, учить ``` Аргументы ведут себя так же, как и в строковом `slice`: [smart header="Совсем как в строках"] Синтаксис метода `slice` одинаков для строк и для массивов. Тем проще его запомнить. [/smart] ## Сортировка, метод sort(fn) Метод `sort()` сортирует массив *на месте*. Например: ```js //+ run var arr = [ 1, 2, 15 ]; arr.sort(); alert( arr ); // *!*1, 15, 2*/!* ``` Не заметили ничего странного в этом примере? Порядок стал `1, 15, 2`, это точно не сортировка чисел. Почему? **Это произошло потому, что по умолчанию `sort` сортирует, преобразуя элементы к строке.** Поэтому и порядок у них строковый, ведь `"2" > "15"`. ### Свой порядок сортировки Для указания своего порядка сортировки в метод `arr.sort(fn)` нужно передать функцию `fn` от двух элементов, которая умеет сравнивать их. Внутренний алгоритм функции сортировки умеет сортировать любые массивы -- апельсинов, яблок, пользователей, и тех и других и третьих -- чего угодно. Но для этого ему нужно знать, как их сравнивать. Эту роль и выполняет `fn`. Если эту функцию не указать, то элементы сортируются как строки. Например, укажем эту функцию явно, отсортируем элементы массива как числа: ```js //+ run function compareNumeric(a, b) { if (a > b) return 1; if (a < b) return -1; } var arr = [ 1, 2, 15 ]; *!* arr.sort(compareNumeric); */!* alert(arr); // *!*1, 2, 15*/!* ``` Обратите внимание, мы передаём в `sort()` именно саму функцию `compareNumeric`, без вызова через скобки. Был бы ошибкой следующий код: ```js arr.sort( compareNumeric*!*()*/!* ); // не сработает ``` Как видно из примера выше, функция, передаваемая `sort`, должна иметь два аргумента. Алгоритм сортировки, встроенный в JavaScript, будет передавать ей для сравнения элементы массива. Она должна возвращать: [smart header="Алгоритм сортировки"] В методе `sort`, внутри самого интерпретатора JavaScript, реализован универсальный алгоритм сортировки. Как правило, это ["\"быстрая сортировка\""](http://algolist.manual.ru/sort/quick_sort.php), дополнительно оптимизированная для небольших массивов. Он решает, какие пары элементов и когда сравнивать, чтобы отсортировать побыстрее. Мы даём ему функцию -- способ сравнения, дальше он вызывает её сам. Кстати, те значения, с которыми `sort` вызывает функцию сравнения, можно увидеть, если вставить в неё `alert`: ```js //+ run [1, -2, 15, 2, 0, 8].sort(function(a, b) { alert(a + " <> " + b); }); ``` [/smart] [smart header="Сравнение `compareNumeric` в одну строку"] Функцию `compareNumeric` для сравнения элементов-чисел можно упростить до одной строчки. ```js function compareNumeric(a, b) { return a - b; } ``` Эта функция вполне подходит для `sort`, так как возвращает положительное число, если `a > b`, отрицательное, если наоборот, и `0`, если числа равны. [/smart] ## reverse Метод [arr.reverse()](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/reverse) меняет порядок элементов в массиве на обратный. ```js //+ run var arr = [1,2,3]; arr.reverse(); alert(arr); // 3,2,1 ``` ## concat Метод [arr.concat(value1, value2, ... valueN)](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/concat) создаёт новый массив, в который копируются элементы из `arr`, а также `value1, value2, ... valueN`. Например: ```js //+ run var arr = [1,2]; *!* var newArr = arr.concat(3,4); */!* alert(newArr); // 1,2,3,4 ``` У `concat` есть одна забавная особенность. Если аргумент `concat` -- массив, то `concat` добавляет элементы из него. Например: ```js //+ run var arr = [1,2]; *!* var newArr = arr.concat( [3,4], 5);// то же самое, что arr.concat(3,4,5) */!* alert(newArr); // 1,2,3,4,5 ``` ## indexOf/lastIndexOf Эти методы не поддерживаются в IE8-. Для их поддержки подключите библиотеку [ES5-shim](https://github.com/kriskowal/es5-shim). Метод ["arr.indexOf(searchElement[, fromIndex])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf) возвращает номер элемента `searchElement` в массиве `arr` или `-1`, если его нет. Поиск начинается с номера `fromIndex`, если он указан. Если нет -- с начала массива. **Для поиска используется строгое сравнение `===`.** Например: ```js //+ run var arr = [ 1, 0, false ]; alert( arr.indexOf(0) ); // 1 alert( arr.indexOf(false) ); // 2 alert( arr.indexOf(null) ); // -1 ``` Как вы могли заметить, по синтаксису он полностью аналогичен методу [indexOf для строк](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/indexOf). Метод ["arr.lastIndexOf(searchElement[, fromIndex])"](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf) ищет справа-налево: с конца массива или с номера `fromIndex`, если он указан. [warn header="Методы `indexOf/lastIndexOf` осуществляют поиск перебором"] Если нужно проверить, существует ли значение в массиве -- его нужно перебрать. Только так. Внутренняя реализация `indexOf/lastIndexOf` осуществляет полный перебор, аналогичный циклу `for` по массиву. Чем длиннее массив, тем дольше он будет работать. [/warn] [smart header="Коллекция уникальных элементов"] Рассмотрим задачу -- есть коллекция строк, и нужно быстро проверять: есть ли в ней какой-то элемент. Массив для этого не подходит из-за медленного `indexOf`. Но подходит объект! Доступ к свойству объекта осуществляется очень быстро, так что можно сделать все элементы ключами объекта и проверять, есть ли уже такой ключ. Например, организуем такую проверку для коллекции строк `"div"`, `"a"` и `"form"`: ```js var store = { }; // объект для коллекции var items = ["div", "a", "form"]; for(var i=0; i
  • `push/pop`, `shift/unshift`, `splice` -- для добавления и удаления элементов.
  • `join/split` -- для преобразования строки в массив и обратно.
  • `sort` -- для сортировки массива. Если не передать функцию сравнения -- сортирует элементы как строки.
  • `reverse` -- меняет порядок элементов на обратный.
  • `concat` -- объединяет массивы.
  • `indexOf/lastIndexOf` -- возвращают позицию элемента в массиве (не поддерживается в IE8-).
  • Изученных нами методов достаточно в 95% случаях, но существуют и другие. Для знакомства с ними рекомендуется заглянуть в справочник Array и [Array в Mozilla Developer Network](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array).