Вызываемые объекты, не являющиеся функциями, встречаются в современных реализациях JavaScript в двух ситуациях. Во-первых, веб-броузер IE (версии 8 и ниже) реализует клиентские методы, такие как
<b>Window.alert()</b>
и
<b>Document.getElementsByld(),</b>
используя вызываемые объекты, а не объекты класса
<b>Function</b>
. Эти методы действуют в IE точно так же, как в других броузерах, но они не являются объектами
<b>Function</b>
. В IE9 был выполнен переход на использование настоящих функций, поэтому со временем эта разновидность вызываемых объектов будет использоваться все меньше и меньше.
Другой типичной разновидностью вызываемых объектов являются объекты
<b>RegExp</b>
- во многих броузерах предоставляется возможность напрямую вызывать объект
<b>RegExp</b>
, как более краткий способ вызова его метода
<b>ехес().</b>
Эта возможность не предусматривается стандартом JavaScript. В свое время она была реализована компанией Netscape и подхвачена другими производителями для обеспечения совместимости. Старайтесь не писать программы, опирающиеся на возможность вызова объектов
<b>RegExp</b>
: данная особенность, скорее всего, будет объявлена нерекомендуемой и будет ликвидирована в будущем. Оператор
<b>typeof</b>
не во всех броузерах одинаково распознает вызываемые объекты
<b>RegExp</b>
. В одних броузерах он возвращает строку «function», а в других - «object».
Если в программе потребуется определить, является ли объект настоящим объектом функции (и обладает методами функций), сделать это можно, определив значение атрибута class (раздел 6.8.2), использовав прием, продемонстрированный в примере 6.4:
<b>function isFunction(x) {</b>
<b>return Object.prototype.toString.call(x) === "[object Function]";</b>
<b>}</b>
Обратите внимание, насколько эта функция
<b>isFunction()</b>
похожа на функцию
<b>isArray(),</b>
представленную в разделе 7.10.
8.8. Функциональное программирование
JavaScript не является языком функционального программирования, как
<b>Lisp</b>
или
<b>Haskell</b>
, но тот факт, что программы на языке JavaScript могут манипулировать функциями как объектами означает, что в JavaScript можно использовать приемы функционального программирования. Масса методов в ECMAScript 5, таких как
<b>mар()</b>
и
<b>reduce(),</b>
сами по себе способствуют использованию функционального стиля программирования. В следующих разделах демонстрируются приемы функционального программирования на языке JavaScript. Их цель - не подтолкнуть вас к использованию этого замечательного стиля программирования, а показать широту возможностей функций в языке JavaScript.
15 8.8.1. Обработка массивов с помощью функций
Представим, что у нас имеется массив чисел и нам необходимо найти среднее значение и стандартное отклонение для этих значений. Эту задачу можно было бы решить без использования приемов функционального программирования, как показано ниже:
<b>var data = [1,1,3,5,5]; // Массив чисел</b>
<b>// Среднее - это сумма значений элементов, деленная на их количество </b>
<b>var total = 0;</b>
<b>for(var і = 0; і < data.length; і++) total += data[i]; </b>
<b>var mean = total/data.length; // Среднее значение равно З</b>
<b>// Чтобы найти стандартное отклонение, необходимо вычислить сумму квадратов </b>
<b>// отклонений элементов от среднего, </b>
<b>total = 0;</b>
<b>for(var і = 0; і < data.length; i++) {</b>
<b> var deviation = data[i] - mean; </b>
<b> total += deviation * deviation;</b>
<b>}</b>
<b>var stddev = Math.sqrt(total/(data.length-1)); // Стандартное отклонение = 2</b>
Те же вычисления можно выполнить в более кратком функциональном стиле, задействовав методы массивов
<b>mар()</b>
и
<b>reduce(),</b>
как показано ниже (краткое описание этих методов приводится в разделе 7.9):
<b>// Для начала необходимо определить две простые функции </b>
<b>var sum = function(x,у) { return х+у; }; </b>
<b>var square = function(x) { return x*x; };</b>
<b>// Затем использовать их совместно с методами класса Array для вычисления</b>
<b>// среднего и стандартного отклонения</b>
<b>var data = [1,1,3,5,5];</b>
<b>var mean = data.reduce(sum)/data.length;</b>
<b>var deviations = data.map(function(x) {return x-mean;});</b>
<b>var stddev = Math.sqrt(deviations.map(square).reduce(sum)/(data.length-1));</b>
A как быть, если в нашем распоряжении имеется только реализация ЕСМА-Script 3, где отсутствуют эти новейшие методы массивов? Можно определить собственные функции mар() и reduce(), которые будут использовать встроенные методы при их наличии:
<b>// Вызывает функцию f для каждого элемента массива и возвращает массив результатов.</b>
<b>// Использует метод Array.prototype.mар, если он определен, </b>
<b>var mар = Array.prototype.тар</b>
<b> ? function(a, f) { return a.map(f); } // Если метод map() доступен </b>
<b> : function(a,f) { // Иначе реализовать свою версию</b>