Функции

This article is in need of an editorial review.

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

Объявление функций

Объявление функции состоит из ключевого слова function, далее следует:

  • Имя функции.
  • Список аргументов функции, в скобках вида ( ) разделенных запятыми (или параметров функции по другому).
  • Инструкции JavaScript которые и составляют тело функции обрамляются, скобками вида { }.

Пример, следующий код объявляет функцию  square:

function square(number) {
  return number * number;
}

Функция square принимает один аргумент number. Функция состоит из одной иструкции которая дословно говорит: вернуть аргумент функции (тот что имеет имя number) умноженый на себя. Инструкция return указывает значение возвращаемое функцией.

return number * number;

Параметры примитивы (такие как напримеh числа) передаются в функции по значению; значение передается функции, но если функция изменит значение параметра, это изменение не будет иметь глобального эффекта.

Если вы передаете в функцию объект (непримитивное значение, такой как Array или определенный пользователем объект) как параметр, и функция изменяет свойства объекта, то эти изменения будут видимы вне функции, как продемонстрировано это в след. примере:

function myFunc(theObject) {
  theObject.make = "Toyota";
}

var mycar = {make: "Honda", model: "Accord", year: 1998},
    x,
    y;

x = mycar.make;     // x gets the value "Honda"

myFunc(mycar);
y = mycar.make;     // y gets the value "Toyota"
                    // (the make property was changed by the function)

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

function myFunc(theObject) {
  theObject = {make: "Ford", model: "Focus", year: 2006};
}

var mycar = {make: "Honda", model: "Accord", year: 1998},
    x,
    y;

x = mycar.make;     // x gets the value "Honda"

myFunc(mycar);
y = mycar.make;     // y still gets the value "Honda" 

В первом случае, объект mycar был передан в функцию myFunc, котороя измденяля его состояние. Во втором случае, функция не изменяла переданный объект; вместо этого, она создавала новую локальную переменную с тем же именем что и имя параметра функции, так что никак не влияет на глобальный объект передаваемый в функцию.

В JavaScript, функция может определяться в условном выражении. Например, функция myFunc будет определена только если num равно 0:

if (num == 0){
  function myFunc(theObject) {
    theObject.make = "Toyota"
  }
}

Если num не равно 0, то функция не будет определена и любая попытка ее вызвать вызовет ошибку выполнения.

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

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

Вдобавок к определению функций как было описано ранее, вы также можете использовать Function конструктор чтобы создавать функции из строки во время выполнения, как это делает eval().

Метод это функция являющаяся членом объекта. Больше информации об объектах и методах в Работа с Объектами.

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

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

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

var factorial = function fac(n) {return n<2 ? 1 : n*fac(n-1)};

print(factorial(3));

Функции выражения очень удобны когда надо передать в функцию другую функцию как аргумент. След. пример иллюстрирует определение функции map и далее следует вызов анонимной функции, которая передана туда как первый параметр:

function map(f,a) {
  var result = [], // Create a new Array
      i;
  for (i = 0; i != a.length; i++)
    result[i] = f(a[i]);
  return result;
}

Следующий код:

map(function(x) {return x * x * x}, [0, 1, 2, 5, 10]);

вернет [0, 1, 8, 125, 1000].

Вызов функций

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

square(5);

Предыдущая инструкция вызывает функцию с аргументом равным 5. Функция выполняет свои инструкции и возвращает значение 25.

Функции должны быть в области видимости, когда они вызываются, но объявление функции может быть и после вызова, как в примере ниже:

print(square(5));
/* ... */
function square(n){return n*n} 

Область видимости функции это функция в которой она объявлена, или вся программа если она объявлена на самом верхнем уровне. Заметьте что код приведенный в примере выше сработает только если вы используете такой же синтаксис определения функции (т.е. function funcName(){}). Код ниже работать не будет.

print(square(5));
square = function (n) {
  return n * n;
}

Аргументы функции не ограничены числами и строками. Вы также можете передавать объекты и функции. Функция show_props (определенная в Работа с Объектами) пример функции которая берет объект как аргумент.

Функция может быть рекурсивной; она может вызвать саму себя. Классический пример рекурсивной функции вычисляющей факториал:

function factorial(n){
  if ((n == 0) || (n == 1))
    return 1;
  else
    return (n * factorial(n - 1));
}

Вы можете вычислить факторил от одного до пяти след.образом:

var a, b, c, d, e;
a = factorial(1); // a gets the value 1
b = factorial(2); // b gets the value 2
c = factorial(3); // c gets the value 6
d = factorial(4); // d gets the value 24
e = factorial(5); // e gets the value 120

Существуют и другие способы вызывать функции. Бывают случаи когда функцию нужно вызывать динамически, или количество аргументов изменяется, или контекс, в котором должна быть вызвана функция, нужно привести к объекту определяемому во время выполнения. Оказывается что фукции сами являются объектами и содержат в себе методы (смотрите Function объект). Один из них, метод apply(), может использоваться для достижения этих целей.

Область видимости функции

Переменные определенные внутри функции невидимы вне этой функции, так как переменные определяются в области видимости внутри функции. Как бы там ни было сама функция имеет доступ ко всем переменным и другим функциям определенным в той же области видимости где и сама функция была определена. Другими словами, функция определенная в глобальной области видимости имеет доступ ко всем переменным определенным в глобальной области видимости. Функция определенная внутри другой функции имеет доступ ко всем переменным определенным в функции родителе и любой другой переменной к которой функция родитель имеет доступ..

// The following variables are defined in the global scope
var num1 = 20,
    num2 = 3,
    name = "Chamahk";

// This function is defined in the global scope
function multiply() {
  return num1 * num2;
}

multiply(); // Returns 60

// A nested function example
function getScore () {
  var num1 = 2,
      num2 = 3;
  
  function add() {
    return name + " scored " + (num1 + num2);
  }
  
  return add();
}

getScore(); // Returns "Chamahk scored 5"

Замыкания

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

var pet = function(name) {          // The outer function defines a variable called "name"
      var getName = function() {
        return name;                // The inner function has access to the "name" variable of the outer function
      }

      return getName;               // Return the inner function, thereby exposing it to outer scopes
    },
    myPet = pet("Vivie");
    
myPet();                            // Returns "Vivie"

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

var createPet = function(name) {
  var sex;
  
  return {
    setName: function(newName) {
      name = newName;
    },
    
    getName: function() {
      return name;
    },
    
    getSex: function() {
      return sex;
    },
    
    setSex: function(newSex) {
      if(typeof newSex == "string" && (newSex.toLowerCase() == "male" || newSex.toLowerCase() == "female")) {
        sex = newSex;
      }
    }
  }
}

var pet = createPet("Vivie");
pet.getName();                  // Vivie

pet.setName("Oliver");
pet.setSex("male");
pet.getSex();                   // male
pet.getName();                  // Oliver

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

var getCode = (function(){
  var secureCode = "0]Eal(eh&2";    // A code we do not want outsiders to be able to modify...
  
  return function () {
    return secureCode;
  };
})();

getCode();    // Returns the secret code

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

var createPet = function(name) {  // Outer function defines a variable called "name"
  return {
    setName: function(name) {    // Enclosed function also defines a variable called "name"
      name = name;               // ??? How do we access the "name" defined by the outer function ???
    }
  }
}

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

Использование объекта аргументов

Аргументы функции содержатся в объекте похожем на массив. Внутри функции вы можете получить доступ к аргументам следующим образом:

arguments[i]

где i - порядковый номер аргумента, начиная с нуля. Таким образом, первый аргумент переданный в функцию будет arguments[0]. Общее количество аргументов можно определить вызовом arguments.length.

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

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

function myConcat(separator) {
   var result = "", // initialize list
       i;
   // iterate through arguments
   for (i = 1; i < arguments.length; i++) {
      result += arguments[i] + separator;
   }
   return result;
}

Вы можете передавать любое количество аргументов в эту функцию, и она объединит все аргументы в единую строку "list":

// returns "red, orange, blue, "
myConcat(", ", "red", "orange", "blue");

// returns "elephant; giraffe; lion; cheetah; "
myConcat("; ", "elephant", "giraffe", "lion", "cheetah");

// returns "sage. basil. oregano. pepper. parsley. "
myConcat(". ", "sage", "basil", "oregano", "pepper", "parsley");

Заметьте, что переменная arguments обладает свойствами массива, но не является им. Сходство с массивом обусловлено тем, что эта переменная имеет индекс и свойство length, но она не обладает остальными методами манипуляции массивом.

Смотрите объект Function в Справочнике JavaScript для получения дополнительной информации.

Функции высшего уровня

В JavaScript есть несколько встроенных функций высшего уровня:

Следующие секции описывают эти функции. Смотрите JavaScript Справочник чтобы получить больше информации по этим функциям.

Функция eval

Функция eval вычисляет строку кода JavaScript без отсылки к конкретному объекту. Синтаксис функции eval:

eval(expr);

где expr - строка, подлежащая вычислению.

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

Функция isFinite

Функция isFinite определяет является ли ее аргумент конечным числом. Синтаксис функции isFinite:

isFinite(number);

где number - число, подлежащее оценке.

Если аргумент представляет собой NaN, а также положительную или отрицательную бесконечность, то функция возвращает false, в противном случае - true.

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

if(isFinite(ClientInput)){
   /* take specific steps */
}

Функция isNaN

Фнкция isNaN определяет является ли аргумент "NaN" (не числом). Синтаксис функции isNaN:

isNaN(testValue);

где testValue - величина, подлежащая проверке.

Функции parseFloat и parseInt возвращают "NaN" когда их аргументом является не число. isNaN возвращает true если ее аргументом является "NaN," и false - в противном случае.

Следующий код выполняет проверку аргумента floatValue, определяя является ли тот числом, и затем вызывает соответствующую процедуру:

var floatValue = parseFloat(toFloat);

if (isNaN(floatValue)) {
   notFloat();
} else {
   isFloat();
}

Функции parseInt и parseFloat

Данные "parse"-функции, parseInt и parseFloat, возвращают соответсвующую численную величину если в качестве их аргумента задана строка.

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

parseFloat(str);

где parseFloat анализирует свой агрумент, строку str, и пытается вернуть соответстующее ей число с плавающей запятой. Если функция встречает символ, отличный от знака числа (+ или -), цифрового символа (0-9), десятичной дроби, или показателя степени, тогда она преобразует часть аргумента до точки встречи такого символа, игнорируя при этом данный символ и все следующие за ним символы. Если первый символ аргрумента не может быть преобразован в число, то функция возвращает "NaN" (не число).

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

parseInt(str [, radix]);

parseInt анализирует свой первый агрумент, строку str, и пытается вернуть целое число с учетом указанного radix (основания системы счисления), определяемого вторым, необязательным аргументом, radix. Например, основание 10 предписывает преобразовать аргумент в десятичное число, 8 - в восьмеричное, 16 - шестнадцатеричное, и так далее. При указании основания более 10 для представления чисел больше девяти используются латинские буквы. Например, для шестнадцатеричных чисел (основание 16), используются буквы от A до F.

Если фукнция parseInt встречает символ, который не согласуется с представлением числа в указанной системе счисления, она игнорирует данный символ и все следующие за ним символы, преобразуя в целое число часть аргумента до точки встречи такого символа. Если первый символ аргрумента не может быть преобразован в число, то функция возвращает "NaN". Функция parseInt округляет результат преобразования строки-аргумента до целого числа.

Функции Number и String

Функции Number и String позволяют преобразовать объект соответственно в число или строку. Синтаксис данных функций:

var objRef;
objRef = Number(objRef);
objRef = String(objRef);

где objRef  - объектная ссылка. Функция Number использует объектный метод valueOf(); функция String использует объектный метод toString().

В следующем примере реализовано преобразование объекта Date в удобочитаемую строку.

var D = new Date(430054663215),
    x;
x = String(D); // x equals "Thu Aug 18 04:37:43 GMT-0700 (Pacific Daylight Time) 1983"

В следующем примере реализовано преобразование объекта String в объект Number.

var str = "12",
    num;
num = Number(str);

Вы можете выполнить проверку преобразования самостоятельно. Для этого используйте DOM-метод write() и оператор JavaScript typeof.

var str = "12",
    num;
document.write(typeof str);
document.write("<br/>");
num = Number(str);
document.write(typeof num);

Функции escape and unescape

Функции escape и unescape не работают корректно с не-ASCII символами и потому упразднены. В JavaScript версии 1.5 и выше используйте функции encodeURI, decodeURI, encodeURIComponent, и decodeURIComponent.

Функции escape и unescape позволяют кодировать и декодировать строки. Функция escape возвращет шестнадцатеричный код аргумента в латинской системе символов ISO. Функция unescape возвращает ASCII-строку для заданной величны шестнадцатеричного кода.

Синтаксис данных функций:

escape(string);
unescape(string);

Данные функции используются в основном в серверной части JavaScript для кодирования и декодирования пар "имя-величина" в строках ссылок (URL).

Метки документа и участники

Contributors to this page: roma-derski, fscholz, andrcmdr, dixon2002, teoli, uleming
Обновлялась последний раз: roma-derski,
Скрыть боковую панель