Метод bind
, который есть у всех функций, создаёт новую функцию, которая вызовет оригинальную, но с некоторыми фиксированными аргументами.
Следующий пример показывает, как это работает. В нём мы определяем функцию isInSet
, которая говорит, есть ли имя человека в заданном наборе. Для вызова filter
мы можем либо написать выражение с функцией, которое вызывает isInSet
, передавая ей набор строк в качестве первого аргумента, или применить функцию isInSet
частично.
var theSet = ["Carel Haverbeke", "Maria van Brussel",
"Donald Duck"];
function isInSet(set, person) {
return set.indexOf(person.name) > -1;
}
console.log(ancestry.filter(function(person) {
return isInSet(theSet, person);
}));
// → [{name: "Maria van Brussel", …},
// {name: "Carel Haverbeke", …}]
console.log(ancestry.filter(isInSet.bind(null, theSet)));
// → … тот же результат
Вызов bind
возвращает функцию, которая вызовет isInSet
с первым аргументом theSet
, и последующими аргументами такими же, какие были переданы в bind
.
Первый аргумент, который сейчас установлен в null
, используется для вызовов методов – так же, как было в apply
. Мы поговорим об этом позже.
Возможность передавать вызов функции другим функциям – не просто игрушка, но очень полезное свойство JavaScript. Мы можем писать выражения «с пробелами» в них, которые затем будут заполнены при помощи значений, возвращаемых функциями.
У массивов есть несколько полезных методов высшего порядка – forEach
, чтобы сделать что-то с каждым элементом, filter
– чтобы построить новый массив, где некоторые значения отфильтрованы, map
– чтобы построить новый массив, каждый элемент которого пропущен через функцию, reduce
– для комбинации всех элементов массива в одно значение.
У функций есть метод apply
для передачи им аргументов в виде массива. Также у них есть метод bind
для создания копии функции с частично заданными аргументами.
Используйте метод reduce
в комбинации с concat
для свёртки массива массивов в один массив, у которого есть все элементы входных массивов.
var arrays = [[1, 2, 3], [4, 5], [6]];
// Ваш код тут
// → [1, 2, 3, 4, 5, 6]
Разница в возрасте матерей и их детей
Используя набор данных из примера, подсчитайте среднюю разницу в возрасте между матерями и их детьми (это возраст матери во время появления ребёнка). Можно использовать функцию average
, приведённую в главе.
Обратите внимание – не все матери, упомянутые в наборе, присутствуют в нём. Здесь может пригодиться объект byName
, который упрощает процедуру поиска объекта человека по имени.
function average(array) {
function plus(a, b) { return a + b; }
return array.reduce(plus) / array.length;
}
var byName = {};
ancestry.forEach(function(person) {
byName[person.name] = person;
});
// Ваш код тут
// → 31.2
Историческая ожидаемая продолжительность жизни
Мы считали, что только последнее поколение людей дожило до 90 лет. Давайте рассмотрим этот феномен поподробнее. Подсчитайте средний возраст людей для каждого из столетий. Назначаем столетию людей, беря их год смерти, деля его на 100 и округляя: Math.ceil(person.died / 100)
.
function average(array) {
function plus(a, b) { return a + b; }
return array.reduce(plus) / array.length;
}
// Тут ваш код
// → 16: 43.5
// 17: 51.2
// 18: 52.8
// 19: 54.8
// 20: 84.7
// 21: 94
В качестве призовой игры напишите функцию groupBy
, абстрагирующую операцию группировки. Она должна принимать массив и функцию, которая вычисляет группу для элементов массива, и возвращать объект, который сопоставляет названия групп массивам членов этих групп.
У массивов есть ещё стандартные методы every
и some
. Они принимают как аргумент некую функцию, которая, будучи вызванной с элементом массива в качестве аргумента, возвращает true
или false
. Так же, как &&
возвращает true
, только если выражения с обеих сторон оператора возвращают true
, метод every
возвращает true
, когда функция возвращает true
для всех элементов массива. Соответственно, some
возвращает true
, когда заданная функция возвращает true
при работе хотя бы с одним из элементов массива. Они не обрабатывают больше элементов, чем необходимо – например, если some
получает true
для первого элемента, он не обрабатывает оставшиеся.
Читать дальше