. Но разделение общего подхода (обход древа) и конкретного случая (подсчёт ДНК) позволяет нам писать более понятный код и использовать вновь части кода для других задач. Например, следующий код выясняет процент известных предков данного человека, доживших до 70 лет.
>function countAncestors(person, test) {
> function combine(person, fromMother, fromFather) {
> var thisOneCounts = test(person);
> return fromMother + fromFather + (thisOneCounts ? 1 : 0);
> }
> return reduceAncestors(person, combine, 0);
>}
>function longLivingPercentage(person) {
> var all = countAncestors(person, function(person) {
> return true;
> });
> var longLiving = countAncestors(person, function(person) {
> return (person.died - person.born) >= 70;
> });
> return longLiving / all;
>}
>console.log(longLivingPercentage(byName["Emile Haverbeke"]));
>// → 0.145
Не нужно относиться к таким расчётам слишком серьёзно, так как наш набор содержит произвольную выборку людей. Но код демонстрирует, что >reduceAncestors
– полезная часть общего словаря для работы со структурой данных типа фамильного древа.
Метод >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. Мы можем писать выражения «с пробелами» в них, которые затем будут заполнены при помощи значений, возвращаемых функциями.
У массивов есть несколько полезных методов высшего порядка –