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

>function greaterThan(n) {

>  return function(m) { return m > n; };

>}

>var greaterThan10 = greaterThan(10);

>console.log(greaterThan10(11));

>// → true

Можно сделать функцию, меняющую другие функции.

>function noisy(f) {

>  return function(arg) {

>    console.log("calling with", arg);

>    var val = f(arg);

>    console.log("called with", arg, "- got", val);

>    return val;

>  };

>}

>noisy(Boolean)(0);

>// → calling with 0

>// → called with 0 - got false

Можно даже делать функции, создающие новые типы управления потоком выполнения программы.

>function unless(test, then) {

>  if (!test) then();

>}

>function repeat(times, body) {

>  for (var i = 0; i < times; i++) body(i);

>}


>repeat(3, function(n) {

>  unless(n % 2, function() {

>    console.log(n, "is even");

>  });

>});

>// → 0 is even

>// → 2 is even

Правила лексических областей видимости, которые мы обсуждали в главе 3, работают нам на пользу в таких случаях. В последнем примере переменная >n – это аргумент внешней функции. Поскольку внутренняя функция живёт в окружении внешней, она может использовать >n. Тела таких внутренних функций имеют доступ к переменным, окружающим их. Они могут играть роль блоков >{}, используемых в обычных циклах и условных выражениях. Важное отличие в том, что переменные, объявленные внутри внутренних функций, не попадают в окружение внешней. И обычно это только к лучшему.

Передача аргументов

Функция >noisy, объявленная ранее, которая передаёт свой аргумент в другую функцию, не совсем удобна.

>function noisy(f) {

>  return function(arg) {

>    console.log("calling with", arg);

>    var val = f(arg);

>    console.log("called with", arg, "- got", val);

>    return val;

>  };

>}

Если >f принимает больше одного параметра, она получит только первый. Можно было бы добавить кучу аргументов к внутренней функции (>arg1, >arg2 и т. д.) и передать все их в >f, но ведь неизвестно, какого количества нам хватит. Кроме того, функция >f не могла бы корректно работать с >arguments.length. Так как мы всё время передавали бы одинаковое число аргументов, было бы неизвестно, сколько аргументов нам было задано изначально.


Для таких случаев у функций в JavaScript есть метод >apply. Ему передают массив (или объект в виде массива) из аргументов, а он вызывает функцию с этими аргументами.

>function transparentWrapping(f) {

>  return function() {

>    return f.apply(null, arguments);

>  };

>}

Данная функция бесполезна, но она демонстрирует интересующий нас шаблон – возвращаемая ею функция передаёт в >f все полученные ею аргументы, но не более того. Происходит это при помощи передачи её собственных аргументов, хранящихся в объекте