// → 1
Ошибки быть не может! Феномен случается именно тогда, когда Жак ест арахис и не чистит зубы. Если б он только не был таким неряхой относительно оральной гигиены, он бы вообще не заметил своего несчастья.
Зная это, Жак просто перестаёт есть арахис и обнаруживает, что трансформации прекратились.
У Жака какое-то время всё хорошо. Но через несколько лет он теряет работу, и в конце концов ему приходится наняться в цирк, где он выступает как Удивительный Человек-белка, набирая полный рот арахисового масла перед шоу. Однажды, устав от столь жалкого существования, Жак не обращается обратно в человека, пробирается через дыру в цирковом тенте и исчезает в лесу. Больше его никто не видел.
Дальнейшая массивология
В конце главы хочу познакомить вас ещё с несколькими концепциями, относящимися к объектам. Начнём с полезных методов, имеющихся у массивов.
Мы видели методы push и pop, которые добавляют и отнимают элементы в конце массива. Соответствующие методы для начала массива называются unshift и shift.
var todoList = [];
function rememberTo(task) {
todoList.push(task);
}
function whatIsNext() {
return todoList.shift();
}
function urgentlyRememberTo(task) {
todoList.unshift(task);
}
Данная программа управляет списком дел. Вы добавляете дела в конец списка, вызывая rememberTo("поесть"), а когда вы готовы заняться чем-то, вызываете whatIsNext(), чтобы получить (и удалить) первый элемент списка. Функция urgentlyRememberTo тоже добавляет задачу, но только в начало списка.
У метода indexOf есть родственник по имени lastIndexOf, который начинает поиск элемента в массиве с конца:
console.log([1, 2, 3, 2, 1].indexOf(2));
// → 1
console.log([1, 2, 3, 2, 1].lastIndexOf(2));
// → 3
Оба метода, indexOf и lastIndexOf, принимают необязательный второй аргумент, который задаёт начальную позицию поиска.
Ещё один важный метод – slice, который принимает номера начального (start) и конечного (end) элементов, и возвращает массив, состоящий только из элементов, попадающих в этот промежуток. Включая тот, что находится по индексу start, но исключая тот, что по индексу end.
console.log([0, 1, 2, 3, 4].slice(2, 4));
// → [2, 3]
console.log([0, 1, 2, 3, 4].slice(2));
// → [2, 3, 4]
Когда индекс end не задан, slice выбирает все элементы после индекса start. У строк есть схожий метод, который работает так же.
Метод concat используется для склейки массивов, примерно как оператор + склеивает строки. В примере показаны методы concat и slice в деле. Функция принимает массив array и индекс index, и возвращает новый массив, который является копией предыдущего, за исключением удалённого элемента, находившегося по индексу index.
function remove(array, index) {
return array.slice(0, index).concat(array.slice(index + 1));
}
console.log(remove(["a", "b", "c", "d", "e"], 2));
// → ["a", "b", "d", "e"]
Строки и их свойства
Мы можем получать значения свойств строк, например length и toUpperCase. Но попытка добавить новое свойство ни к чему не приведёт:
var myString = "Шарик";
myString.myProperty = "значение";
console.log(myString.myProperty);
// → undefined
Величины типа строка, число и булевские – не объекты, и хотя язык не жалуется на попытки назначить им новые свойства, он на самом деле их не сохраняет. Величины неизменяемы.
Но у них есть свои встроенные свойства. У каждой строки есть набор методов. Самые полезные, пожалуй – slice и indexOf, напоминающие те же методы у массивов.
console.log("кокосы".slice(3, 6));
// → осы
console.log("кокос".indexOf("с"));
// → 4
Разница в том, что у строки метод indexOf может принять строку, содержащую больше одного символа, а у массивов такой метод работает только с одним элементом.
console.log("раз два три".indexOf("ва"));
// → 5
Метод trim удаляет пробелы (а также переводы строк, табуляцию и прочие подобные символы) с обоих концов строки.
console.log(" ладно \n ".trim());
// → ладно
Мы уже сталкивались со свойством строки length. Доступ к отдельным символам строчки можно получить через метод charAt, а также просто через нумерацию позиций, как в массиве:
var string = "abc";
console.log(string.length);
// → 3
console.log(string.charAt(0));
// → a
console.log(string[1]);
// → b
Объект arguments
Когда вызывается функция, к окружению исполняемого тела функции добавляется особая переменная под названием arguments. Она указывает на объект, содержащий все аргументы, переданные функции. Помните, что в JavaScript вы можете передавать функции больше или меньше аргументов, чем объявлено при помощи параметров.
function noArguments() {}
noArguments(1, 2, 3); // Пойдёт
function threeArguments(a, b, c) {}
threeArguments(); // И так можно
У объекта arguments есть свойство length, которое содержит реальное количество переданных функции аргументов. Также у него есть свойства для каждого аргумента под именами 0, 1, 2 и т. д.
Если вам кажется, что это очень похоже на массив – вы правы. Это очень похоже на массив. К сожалению, у этого объекта нет методов типа slice или indexOf, что делает доступ к нему труднее.
function argumentCounter() {
console.log("Ты дал мне", arguments.length, "аргумента.");
}
argumentCounter("Дядя", "Стёпа", "Милиционер");
// → Ты дал мне 3 аргумента.
Некоторые функции рассчитаны на любое количество аргументов, как console.log. Они обычно проходят циклом по свойствам объекта arguments. Это можно использовать для создания удобных интерфейсов. К примеру, вспомните, как мы создавали записи для журнала Жака:
addEntry(["работа", "тронул дерево", "пицца", "пробежка", "телевизор"], false);
Так как мы часто вызываем эту функцию, мы можем сделать альтернативу, которую проще вызывать:
function addEntry(squirrel) {
var entry = {events: [], squirrel: squirrel};
for (var i = 1; i < arguments.length; i++)
entry.events.push(arguments[i]);
journal.push(entry);
}
addEntry(true, "работа", "тронул дерево", "пицца", "пробежка", "телевизор");
Эта версия читает первый аргумент как обычно, а по остальным проходит в цикле (начиная с индекса 1, пропуская первый аргумент) и собирает их в массив.