| Роботландский Университет © А.А.Дуванов |
Часто начинающие программисты испытывают трудности в понимании различия между формальными и фактическими аргументами функции.
Можно считать описание функции:
function Sum(a, b)
{
return a+b;
}
документацией на устройство этой функции. Аргументы a и b здесь формальные.
Когда записывается вызов функции
Что происходит дальше? Браузер обращается к документации на функцию Sum и начинает выполнение. Локальным (для функции) переменным a и b (формальным аргументам) браузер присваивает значения 10 и 20. Затем вычисляет сумму и возвращает число 30.
Команда return прерывает выполнение кода функции немедленно. Пусть, например, функция описана так:
function F(a)
{
return 0;
if(a<0) return -a;
}
Вызов F(x) при любом значении x всегда вернет число 0.
Функция, описанная ниже, вычисляет абсолютное значение своего аргумента:
// Функция возвращает модуль числа a.
function abs(a)
{
if(a<0) return -a;
else return a;
}
Эту функцию лучше записать так:
// Функция возвращает модуль числа a.
function abs(a)
{
var ret = a;
if(ret<0) ret = -ret;
return ret;
}
Надо стараться делать один выход из функции и записывать его самым последним.
|
|
| Функция с несколькими выходами похожа на ежа. | Функцию с одним выходом легче понять и проверить. |
Функцию abs можно записать и так:
// Функция возвращает модуль числа a.
function abs(a)
{
if(a<0) a = -a;
return a;
}
Переменная a внутри функции это локальная переменная, ее создает браузер при входе в функцию. Поэтому такая запись допустима. Параметр, который передается в функцию, испорчен не будет. Поясним это на примере:
var x = -2; var y = abs(x);
Выполнение по шагам:
На самом деле, самая красивая (и понятная!) запись для функции abs выглядит так:
// Функция возвращает модуль числа a.
function abs(a)
{
return a > 0 ? a : -a;
}
Необходимости в самодельной функции abs нет. В JavaScript есть встроенный объект Math (смотрите справочник в конце книги). Среди методов этого объекта есть метод abs. Поэтому вычисление модуля x запишется как Math.abs(x).
В Паскале под процедурой понимается именованный код, а под функцией именованный код, возвращающий значение.
В Си и JavaScript процедур нет. Есть только функции. Функция может возвращать значение, и тогда она похожа на функцию Паскаля. Функция может не возвращать значение, и тогда она похожа на процедуру Паскаля.
Функция возвращает значение, когда ее вычисление заканчивается командой return. Вызов такой функции можно использовать в выражениях:
function f(x)
{
return ++x;
}
var y = f(2) + 10;
В этом примере браузер вычислит f(2) и полученное значение 3
подставит вместо f(2) в выражение
Функция может не возвращать значения, и тогда ее нельзя использовать в выражениях, она, подобно процедуре Паскаля, должна стоять в коде отдельной командой:
function g(x)
{
alert(x);
}
var str="Чем мучиться и не жить, лучше жить и не мучиться!";
g(str);
А вот если функция возвращает значение, то ее можно использовать и как процедуру Паскаля. Вычисленное значение при этом просто теряется:
function w(x,str)
{
alert(str);
return ++x;
}
В этом коде:
var str = "Любил я женщин и проказы."; var y = w(2,str);
на экран выводится сообщение, и переменная у получает значение 3. А в этом коде:
var str = "Наш Федя с детства связан был с землею."; w(2,str);
на экран выводится сообщение, а вычисленное значение 3 просто теряется. Попробуйте предсказать, что будет выведено на экран в результате работы такого кода:
function f(x)
{
return x++;
}
var y = f(2) + 10;
alert(y);
Это очень полезная возможность JavaScript. Аргументы, которые передаются в функцию, браузер хранит в виде глобального массива имя_функции.arguments. Первый аргумент, как водится в массивах JavaScript, имеет индекс 0. Число аргументов хранится в свойстве length. Обратиться к нему можно так:
имя_функции.arguments.length
Внутри функции работают более простые обращения:
| arguments[0] | Первый аргумент функции. |
| arguments.length | Число аргументов, переданных в функцию. |
Такой механизм дает приятную возможность передавать в функцию любое число аргументов. Но, конечно, функция должна быть правильно написана.
Рассмотрим пример. Построим функцию, которая вычисляет сумму переданных ей аргументов.
function sum()
{
var s = 0;
for(var i=arguments.length; --i>=0;)
s += arguments[i];
return s;
}
var x, y, z, t;
x = sum(); // x получит значение 0.
y = sum(1); // y получит значение 1.
z = sum(1,2); // z получит значение 3.
t = sum(1,2,3); // t получит значение 6.
В приведенном выше примере функция может иметь любое число аргументов, в том числе и ноль.
Несколько первых аргументов можно сделать обязательными.
// Функция выполняет заданную операцию op
// над своими аргументами.
function calc(op, arg1, arg2)
{
var str = arg1+op+arg2;
var len = arguments.length;
for(var i=3; i<len; i++)
str += op+arguments[i];
return eval(str);
}
var x, y, z, t;
x = calc("+", 1); // Ошибка.
x = calc("+", 1, 2); // x получит значение 3.
y = calc("*",2,3,4); // y получит значение 24.
z = calc("-",10,5,3,1); // z получит значение 1.
t = calc("/",100,5,4); // t получит значение 5.
Замечание. Стандартная функция eval(str) рассматривает свой аргумент str как выражение JavaScript, вычисляет его и возвращает полученное значение.
Если код работает с данными, которые поступают в него извне (например, их вводит пользователь, как в программе Угадайка), то он не должен предполагать, что полученные данные допустимы.
Оборонительный код должен проверить данные перед их впрыском в логику обработки. Проверить и принять адекватные меры: исправить ошибки, если это возможно, или отказать в обработке, выдав диагностику, оговоренную в документации.
Когда код передает управление другому, внешнему коду (вызывает стандартную, библиотечную функцию или функцию, написанную вашим партнером), вы не можете быть уверены, что результат обработки будет именно таким, как это описано в сопроводительной документации или зафиксировано устно в момент обсуждения проекта на кухне за чашкой чая.
В какой-то степени уберечь свой код от краха, следующего за вызовом чужих функций, можно путем тщательного тестирования того, что вы используете.
Ваш собственный код должен быть хорошо спроектирован, документирован и отлажен. Если программные комментарии и внешние описания не соответствуют тому, что делает код на самом деле, то это ловушка, в которую первым обычно попадается сам автор, решивший через какое-то время изменить алгоритм работы кода.
Месяц это предельный срок, в течение которого программист еще помнит, как работает его программа.
|
|