// Возвращает сумму элементов массива (или объекта, подобного массиву) а.
// Все элементы массива должны быть числовыми, при этом значения null
// и undefined игнорируются,
function sum(a) {
if (isArrayLike(a)) {
var total = 0;
for(var і = 0; і < a.length; і++) { // Цикл по всем элементам
var element = a[і];
if (element == null) continue; // Пропустить null и undefined
if (isFinite(element))
total += element;
else throw new Error("sum(): все элементы должны быть числами");
}
return total;
}
else throw new Error("sum(): аргумент должен быть массивом");
}
Этот метод sum()
весьма строго относится к проверке типов входных аргументов и генерирует исключения с достаточно информативными сообщениями, если типы входных аргументов не соответствуют ожидаемым. Тем не менее он остается достаточно гибким, обслуживая наряду с настоящими массивами объекты, подобные массивам, и игнорируя элементы, имеющие значения null
и undefined
.
JavaScript - чрезвычайно гибкий и к тому же слабо типизированный язык, благодаря чему можно писать функции, которые достаточно терпимо относятся к количеству и типам входных аргументов. Далее приводится метод flexsum(),
реализующий такой подход (и, вероятно, являющийся примером другой крайности). Например, он принимает любое число входных аргументов и рекурсивно обрабатывает те из них, которые являются массивами. Вследствие этого он может принимать переменное число аргументов или массив аргументов. Кроме того, он прилагает максимум усилий, чтобы преобразовать нечисловые аргументы в числа, прежде чем сгенерировать исключение:
function flexisum(a) { var total = 0;
for(var і = 0; і < arguments.length; i++) {
var element = arguments[i], n;
if (element == null) continue; // Игнорировать null и undefined
if (isArray(element)) // Если аргумент - массив
n = flexisum.apply(this. element); // вычислить сумму рекурсивно
else
if (typeof element === "function") // Иначе, если это функция...
n = Number(element()); // вызвать и преобразовать,
else
n = Number(element); // Иначе попробовать преобразовать
if (isNaN(n)) // Если не удалось преобразовать в число, возбудить искл.
throw Error("flexisum(): невозможно преобразовать " + element + в число");
total += n; // Иначе прибавить n к total
}
return total;
}
Самые важные особенности функций заключаются в том, что они могут определяться и вызываться. Определение и вызов функции - это синтаксические средства JavaScript и большинства других языков программирования. Однако в JavaScript функции - это не только синтаксические конструкции, но и данные, а это означает, что они могут присваиваться переменным, храниться в свойствах объектов или элементах массивов, передаваться как аргументы функциями и т. д. [13] Это может показаться не столь интересным, если вы не знакомы с такими языками, как Java, в которых функции являются частью программы, но не могут управляться программой.
Чтобы понять, как функции в JavaScript могут быть одновременно синтаксическими конструкциями и данными, рассмотрим следующее определение функции:
function square(x) { return х*х; }
Это определение создает новый объект функции и присваивает его переменной square. Имя функции действительно нематериально - это просто имя переменной, которая ссылается на объект функции. Функция может быть присвоена другой переменной, и при этом работать так же, как и раньше:
var s = square; // Теперь s ссылается на ту же функцию, что и square
square(4); // => 16
s(4); // => 16
Функции могут быть также присвоены не только глобальным переменным, но и свойствам объектов. В этом случае их называют методами:
var о = {square: function(x) { return х*х; }}; // Литерал объекта
var у = о.square(16); // у = 256
Функции могут быть даже безымянными, например, в случае присваивания их элементам массива:
var а = [function(x) { return х*х; }, 20]; // Литерал объекта
а[0](а[1]); // => 400
Синтаксис вызова функции в последнем примере выглядит необычно, однако это вполне допустимый вариант применения выражения вызова!
Читать дальше
Конец ознакомительного отрывка
Купить книгу