Выбрать главу

function isFunction(x) {

return Object.prototype.toString.call(x) === "[object Function]";

}

Обратите внимание, насколько эта функция isFunction() похожа на функцию isArray(), представленную в разделе 7.10.

8.8. Функциональное программирование

JavaScript не является языком функционального программирования, как Lisp или Haskell, но тот факт, что программы на языке JavaScript могут манипулировать функциями как объектами означает, что в JavaScript можно использовать приемы функционального программирования. Масса методов в ECMAScript 5, таких как mар() и reduce(), сами по себе способствуют использованию функционального стиля программирования. В следующих разделах демонстрируются приемы функционального программирования на языке JavaScript. Их цель - не подтолкнуть вас к использованию этого замечательного стиля программирования, а показать широту возможностей функций в языке JavaScript.15

8.8.1. Обработка массивов с помощью функций

Представим, что у нас имеется массив чисел и нам необходимо найти среднее значение и стандартное отклонение для этих значений. Эту задачу можно было бы решить без использования приемов функционального программирования, как показано ниже:

var data = [1,1,3,5,5]; // Массив чисел

// Среднее - это сумма значений элементов, деленная на их количество

var total = 0;

for(var і = 0; і < data.length; і++) total += data[i];

var mean = total/data.length; // Среднее значение равно З

// Чтобы найти стандартное отклонение, необходимо вычислить сумму квадратов

// отклонений элементов от среднего,

total = 0;

for(var і = 0; і < data.length; i++) {

  var deviation = data[i] - mean;

  total += deviation * deviation;

}

var stddev = Math.sqrt(total/(data.length-1)); // Стандартное отклонение = 2

Те же вычисления можно выполнить в более кратком функциональном стиле, задействовав методы массивов mар() и reduce(), как показано ниже (краткое описание этих методов приводится в разделе 7.9):

// Для начала необходимо определить две простые функции

var sum = function(x,у) { return х+у; };

var square = function(x) { return x*x; };

// Затем использовать их совместно с методами класса Array для вычисления

// среднего и стандартного отклонения

var data = [1,1,3,5,5];

var mean = data.reduce(sum)/data.length;

var deviations = data.map(function(x) {return x-mean;});

var stddev = Math.sqrt(deviations.map(square).reduce(sum)/(data.length-1));

A как быть, если в нашем распоряжении имеется только реализация ЕСМА-Script 3, где отсутствуют эти новейшие методы массивов? Можно определить собственные функции mар() и reduce(), которые будут использовать встроенные методы при их наличии:

// Вызывает функцию f для каждого элемента массива и возвращает массив результатов.

// Использует метод Array.prototype.mар, если он определен,

var mар = Array.prototype.тар

    ? function(a, f) { return a.map(f); } // Если метод map() доступен

    : function(a,f) { // Иначе реализовать свою версию

  var results = [];

  for(var і = 0, len = a.length; і < len; і++) {

    if (і in a) results[i] = f.call(null, a[i], і, a);

  }

  return results;

};

// Выполняет свертку массива в единственное значение, используя функцию f

// и необязательное начальное значение. Использует метод Array.prototype.reduce,

// если он определен.

var reduce = Array.prototype.reduce

  ? function(a, f, initial) { // Если метод reduce() доступен,

    if (arguments.length > 2)

      return a.reduce(f, initial); // Если указано начальное значение,

    else return a.reduce(f); // Иначе без начального значения.

  }

вернуться

15

(Если эта тема вам любопытна, вероятно, вас заинтересует возможность использования (или хотя бы знакомства) библиотеки Functional JavaScript Оливера Стила (Oliver Steel), которую можно найти по адресу: http://osteele.com/sources/javascript/functional/