Выразительный JavaScript (Хавербеке) - страница 55

. Но разделение общего подхода (обход древа) и конкретного случая (подсчёт ДНК) позволяет нам писать более понятный код и использовать вновь части кода для других задач. Например, следующий код выясняет процент известных предков данного человека, доживших до 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. Мы можем писать выражения «с пробелами» в них, которые затем будут заполнены при помощи значений, возвращаемых функциями.

У массивов есть несколько полезных методов высшего порядка –