Опубликован: 01.07.2011 | Уровень: для всех | Доступ: платный
Лекция 6:

Функции JavaScript

< Лекция 5 || Лекция 6 || Лекция 7 >
Аннотация: Синтаксис функции. Использование функции. Аргументы. Возвращаемые значения.

Введение

Функции лежат в основе практически всего полезного, что можно сделать с помощью JavaScript. Вообще говоря, они предлагают возможность разбить программу на логические куски, каждый из которых реализует определенный фрагмент функциональности. Они являются центральным элементом языка, и существенная часть привлекательности JavaScript обусловлена специфическими способами, которыми можно создавать и использовать функции. Если вы программировали раньше на таких языках как PHP или Java, то вы не будете испытывать никаких затруднений с функциями в JavaScript. Функции являются критически важными, но они не заставят вас слишком ломать голову. В этой лекции объясняется, почему необходимо понимать функции, затем рассматривается синтаксис, после чего показано, как создавать и использовать их.

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

Лекция имеет следующую структуру:

  • Что и почему
  • Синтаксис функции
    • Использование функции
    • Аргументы
    • Возвращаемые значения
  • Заключение
  • Контрольные вопросы

Что и почему

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

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

Более того, разбиение кода на хорошо продуманные функции значительно облегчает в будущем обслуживание кода. Представьте, например, что правила перехода на летнее время снова изменились в следующем году. Если вы выполняете эти вычисления девяносто пять раз в течение проекта, вы можете внести новые ошибки при обновлении кода в каждом из этих мест; это повторяющаяся, ручная и подверженная ошибкам работа. С другой стороны, изменение одной функции calculateDaylightSavings позволяет распространить это единственное изменение по всей программе с помощью одного исправления, точно также как CSS распространяет стилевое оформление на странице. Таким образом, функции делают обслуживание значительно менее подверженным ошибкам, и облегчают успешную реализацию.

Синтаксис функции

Определение функции является простой задачей. В качестве примера давайте создадим функцию, которая генерирует случайный цвет фона для элемента на странице (http://dev.opera.com/articles/view/javascript-functions/functions_1.html):

function setElementBackground() {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById('element_to_change');
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
  }
}

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

  1. Объявление функции всегда начинается с ключевого слова function, что, конечно, имеет смысл.
  2. Следующим моментом является имя функции, в данном случае setElementBackground (я обычно использую для имен функций camelCase - горбатыйРегистр (https://secure.wikimedia.org/wikipedia/en/wiki/CamelCase)). Имя функции является важным, так как его надо помнить, чтобы использовать и повторно использовать код. Лучше всего, когда оно точно описывает, что делает функция; я думаю, все согласятся, что setElementBackground (задатьФонЭлемента) значительно лучше, более описательное имя функции, чем что-нибудь вроде coloursAreNice (цветаПрекрасны) или crazySetter (безумныеНастройки).
  3. Сразу после имени функции следует пара скобок. Внутри них находится список аргументов функции, который позволяет придать функции более общий вид, и тем самым позволяет легко использовать ее многократно в большем количестве случаев. Это важная концепция, но необязательная, поэтому она подробнее обсуждается в следующем разделе.
  4. Наконец дальше следует пара фигурных скобок, содержащих некоторый код: это означает в JavaScript блок кода. Все внутри этого блока будет выполняться, когда вызывается функция, в определенном порядке, также как и любой другой фрагмент написанного кода JavaScript.

Использование функции

Теперь, когда функция определена, чтобы вызвать ее где-то в коде, необходимо просто написать:

setElementBackground();

Вот и все! Вам не нужно больше заботиться о сложных внутренних деталях setElementBackground ; вы уже написали код, поэтому теперь можно легко использовать его в любом другом месте и пожинать (случайные) вознаграждения за повторное использование.

Теперь только что написанная функция является полностью самодостаточной. Она выполняет некоторые действия, а затем завершается, она не нуждается во вводе из кода, который ее вызывает, и не возвращает вызывающей стороне никакой информации о том, что произошло. JavaScript, конечно, позволяет писать код, который несколько более словоохотлив и гибок, чем этот, поэтому давайте посмотрим, как использовать ввод и вывод информации из функций.

Аргументы

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

Ранее было отмечено, что определение функции содержит пару скобок сразу после имени функции. Это список аргументов функции. Чтобы принять ввод от вызывающей стороны, задайте просто разделенный запятыми список переменных, которые ваша функция хотела бы получить. Можно определить сколько угодно аргументов, и используемые в списке аргументов имена можно использовать внутри тела функции также как любые другие переменные. Обновленная функция setElementBackground выглядит следующим образом (проверьте улучшенный первый пример на практике: http://dev.opera.com/articles/view/javascript-functions/functions_2.html):

function setElementBackground( elementID ) {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById( elementID );
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
  }
}

Вызов этой функции с ID элемента, передаваемым в качестве аргумента, будет очевиден:

setElementBackground( 'element_to_change' );

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

if ( elementID == undefined) {
  // Это условие будет `true` если переменная `elementID`
  // не была определена вызывающей стороной.
  // Затем можно написать некоторый код внутри этого 
  //  оператора if, чтобы остановить код от порождения ошибки.
}

Немного смущающий, но хороший, факт об аргументах функции состоит в том, что имена переменных в списке аргументов не имеют ничего общего с именами переменных, передаваемых в функцию. Если elementID определяется как аргумент функции, JavaScript создает переменную внутри функции с именем elementID, которая не оказывает никакого влияния на переменные вне функции - можно иметь другую переменную, вне этой функции, с таким же именем, и ее значение не изменится в результате выполнения операторов в функции. Например:

var elementID = "No change!";
setElementBackground( 'element_to_change' );
alert( elementID ); // Alerts "No change!";

Это имеет очень важный побочный эффект. JavaScript создает новую переменную внутри функции, что означает, что любые изменения, которые происходят с внутренним аргументом, не оказывают никакого влияния на любую переменную, передаваемую внутрь. Я скажу немного больше об этой концепции (называемой областью действия) в "Объекты в JavaScript" об объектах, а пока рассмотрим небольшой пример. Я определяю функцию Substring (подстрока), получающую строку и начальную позицию:

function substring( obj, start ) {
  obj = obj.substring(start);
}

var myString = "This is a string!";
substring(myString, 8);
alert(myString); // Alerts "This is a string!"

Даже хотя переменная obj переназначается внутри функции результату встроенного метода substring, переменная myString никак не изменяется, изменилась только копия myString, находящаяся внутри substring. Внешняя переменная не имеет никакого представления о том, что что-то произошло.

Это поднимает вопрос коммуникации: если изменение значений аргументов не имеет никакого влияния вне функции, как информация передается назад из функции вызывающей стороне? Давайте на это посмотрим.

Возвращаемые значения

На самом деле достаточно распространено, что функция выполняет некоторые вычисления, и выдает результат этой работы вызывающей стороне для использования в другом месте. Может быть полезно, например, чтобы наша функция setElementBackground возвращала массив значений цвета для использования в другом месте. Это решается просто использованием имеющегося в JavaScript ключевого слова return, как показано ниже:

function setElementBackground( elementID ) {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById( elementID );
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
  }
  return [ red, green, blue ];
}

посмотрите на улучшенный второй пример в действии (http://dev.opera.com/articles/view/javascript-functions/functions_3.html).

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

var my_result = setElementBackground('element_to_change');

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

function setElementBackground( elementID ) {
  var red = Math.floor(Math.random() * 256);
  var green = Math.floor(Math.random() * 256);
  var blue = Math.floor(Math.random() * 256);

  var obj = document.getElementById( elementID );
  if ( obj ) {
    obj.style.background = 'rgb(' + red + ',' + green + ',' + blue + ')';
    return [ red, green, blue ];
  } else {
    return false;
  }
}

посмотрите в действии третий усовершенствованный пример (http://dev.opera.com/articles/view/javascript-functions/functions_4.html).

Это позволяет контролировать, что код выполнился правильно, проверяя, например, возвращаемое значение:

if ( !setElementBackground('element_does_not_exist') ) {
  alert("Что-то пошло неправильно!  'element_does_not_exist' не существует!");
}

Кроме того, обратите внимание, что ключевое слово return в действительности завершает выполнение функции сразу, как только оно вызывается, возвращая процесс выполнения в точку, в которой была вызвана функция. Код, расположенный ниже вызова return, не выполняется - он просто игнорируется.

Заключение

Теперь вы знаете почти все, что нужно, чтобы начать активно использовать функции в коде. Они являются фундаментальной частью хорошего кода JavaScript, и программы будут лучше организованы, чище и более удобочитаемыми, и станут легче для понимания, если вы воспользуетесь возможностью поместить код в хорошо именованные функции для повторного использования.

Контрольные вопросы

  • Что такое функции? Почему они полезны?
  • Как определяется функция?
  • Как информация передается в функцию? Зачем это нужно? И наоборот, как можно получить информацию из функции?
  • Было бы неплохо, если бы можно было передавать в 'setElementBackground' массив цветов? Попробуйте изменить код, чтобы получать еще один аргумент, и используйте эту переменную внутри функции для переопределения случайных цветов фона.

Об авторе


Майк Вест является студентом философии, который ловко маскируется под опытного и успешного web-разработчика. Он работает с web более десяти лет, в последнее время в команде, которая отвечает за создание европейских новостных сайтов Yahoo!.

После того как он покинул в 2005 году широкие пригородные равнины Техаса, Майк поселился в Мюнхене, Германия, где он сражается с языком каждый день все в меньшей степени. mikewest.org (http://mikewest.org/) является его домом в web, собирающим (понемногу) его письменные творения и ссылки для потомства. Он хранит свой код на сайте GitHub (http://github.com/mikewest).

< Лекция 5 || Лекция 6 || Лекция 7 >
Сергей Крупко
Сергей Крупко
Как оплатить курс?
Галина Башкирова
Галина Башкирова
Темы Вкр для проф. переподготовки Профессиональное веб-программирование
Наталья Алмаева
Наталья Алмаева
Россия
Роман Паранин
Роман Паранин
Россия, Ярославль