HTML, Excel, Word, SEOОсновы JavaScript ⇒ Функции JS

ОСНОВЫ JavaScript

Учебник JavaScript
·Знакомство с JS. Переменные, операторы, операции
·Функции
·Модель HTML документа
·Иерархия документов в бразуере
·Формы
·Окна и фреймы
·Ссылки, заголовок, статус
·События
·События клавиатуры и мыши
·События. Таймер
·Стили. Управление стилями
·Слои и блоки. Управление видимостью
·Объекты JS
·Внешние объекты
·Внутренние объекты
·Массивы
·Регулярные выражения
·Математика в JS
·Пример простого калькулятора
·Дата и время
·Cookies и хранение состояния
·Немного об AJAX
·Работа с WebMoney

 

Функции JS



Создание функций

Стандартные функции

Параметры функций. Области видимости. Значение и ссылка

Создание функций.

Те скрипты, которые мы рассматривали до этого времени, были очень небольшими, можно сказать – на один экран редактора. И весь код был виден одновременно. Но если представить, что скрипт занимает не пятнадцать строчек, а все полторы тысячи – как в нем разобраться?  

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

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

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

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

function diff(a,b) { 
	if (a>b) {
		return a – b;
	} else {
		return b – a;
	}
}

В этом коде объявляется функция под именем diff (именно так к ней можно будет обращаться в тексте программы). Эта функция ожидает два параметра – a и b.

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

Оператор return (да, это еще один оператор, который можно применять только внутри тела функции) завершает выполнение блока кода и возвращает значение, если оно есть.

Эта функция может быть вызвана вот так: 

var c = diff(4, 7);
var d = diff(c, 12);

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

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

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

Думаю, вас не удивит тот факт, что внутри одной функции можно вызывать другую функцию (если вызываемая функция уже объявлена). 

Например: 

function inner(a) { 
	return a + 2;
} 
function outer(x) {
	var intermediate = inner(x);
	intermediate += inner(x*x);
	return intermediate;
}

Кстати, таким же образом функция может вызывать сама себя. Такой вызов называется рекурсией.  

Вот, пример простой функции с рекурсией: 

function countback(num) { 
	if (num > 0) {
		alert(num);
		countback(num-1);
	}
} 

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

В чем-то такие рекурсивные функции похожи на циклы (и большую часть циклов можно переписать в виде рекурсивных функций, и наоборот). 

В рекурсивной функции обязательно есть условие и какой-нибудь изменяемый параметр. 

Если вы вспомните предыдущую главу, то также вспомните, что функция в JavaScript тоже является типом. И функцию можно записать в переменную. Поначалу это кажется странным, особенно для тех, кто уже сталкивались с языками вроде C, Java или PHP. 

Но на самом деле ничего сложного в этом нет. 

Например, вот такая запись: 

function fnc(a) {
	return a + 1;
}

var f = fnc; 

создаст функцию fnc() и запишет ее в переменную f.

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

Итак, при исполнении браузером этого кода будет создана функция. Из записи понятно, что она будет получать один параметр, и будет возвращать значение. 

При этом возможен как вызов функции напрямую, при помощи имени fnc(), так и посредством переменной f, тоже – просто написав скобки за именем. Вот так : f()

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

Например, такой код будет вполне работоспособным (и, кроме того, этот способ часть используется и приносит неплохие результаты): 

function compare(a) { 
	return a > 12;
}
var user_func = compare;

function check (arr, fn) {
	var passed = 0;
	for (var i=0; i<arr.length; i++) {
		if (fn(arr[i])) {
			passed++;
		}
	}
	return passed;
}

alert (check([1,5,15,34,2,32,44], user_func)); 

Причем, в качестве второго параметра можно передавать сразу функцию, не утруждаясь занесением ее функции в переменную. 

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

Стандартные функции.

Их, на удивление, не так уж и много. Большая часть полезных функций разнесена по встроенным объектам языка (и браузера). Но все же нашлось несколько таких функций, которые невозможно было отнести к какому-нибудь объекту. 

Вот они: 

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

var a  = String(23);

вполне допустимы. 

Сейчас вы можете спросить, почему в этом списке нет функции alert().

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

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

Например, когда мы вместо того чтобы написать 

var a = 2; 

пишем  

a = 2;

мы добавляем переменную a к объекту window. При этом, следует заметить, есть некоторые тонкости. Использование необъявленной переменной вызовет ошибку, а использование необъявленного свойства объекта просто вернет undefined

Параметры функций. Области видимости. Значение и ссылка.

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

Например, объявляем мы функцию вот так: 

function x(a,b,c) {  
} 

А вызываем так: 

x(1,2);

Как вы думаете, что будет? 

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

Просто при вызове этой функции параметры a и b примут соответственно значения 1 и 2, а вот параметр c окажется undefined

Также мы могли бы написать и  

x(1,2,3,4,5);

И даже в этом случае никакой ошибки не будет. Параметры 4 и 5 никуда не исчезнут, а будут находиться в «труднодоступных» местах. 

Здесь стоило бы немного больше сказать о том, что функция является объектом. 

Так, у любой функции после создания есть свойства и методы (если я еще не говорил, то методом называется свойство, являющееся функцией – запутано, правда?). Например, для объявленной выше функции x можно вызвать метод toString():

var a = x.toString();

И в результате в переменой a окажется строка «function x(a,b,c){}»

Кроме этого, внутри тела функции всегда можно использовать объект arguments, при помощи которого и можно было бы добраться до параметров 4 и 5 при вызове функции с помощью команды

x(1,2,3,4,5); 

Кроме того, следует сказать о передаче параметров по ссылке. 

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

Но в случае, если в функцию передается объект (или массив, или даже функция) – все происходит немного иначе. 

Дело в том, что даже когда мы просто присваиваем переменной значение объекта, эта переменная хранит не сам объект, а только ссылку на него.  

В результате, после таких команд 

var a = {'a':1}; 
var b = a; 

обе переменные будут указывать на один и тот же объект, и при таком вот действии 

a.x = 2; 

можно будет обращаться к b.x, и там будет содержаться та же самая двойка.

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

Такое поведение объектов иногда причиняет неудобства программисту – иногда приходится идти на ухищрения, чтобы получить копию объекта, но очень часто это бывает удобно. 

Учитывая такую разницу в поведении разных типов, было бы неплохо определять, с каким собственно типом приходится работать. И для этого в языке JavaScript существуют целых два оператора – typeof и instanceof.

Первый из них возвращает тип операнда (в виде строки) – например,  

typeof {a:1}; 

вернет строку «object»

Второй оператор показывает, является ли первый операнд (объект) экземпляром второго операнда (тоже объекта). Это полезно в том случае, когда нам нужно проверить, является ли переданный объект массивом или, например, датой (то есть это объект – экземпляр встроенного объекта Array или встроенного объекта Date). Но об этом операторе, а также о вопросах наследований и объектов я расскажу в соответствующей главе.

А сейчас вернемся к функциям. 

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

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

При этом стоит заметить, что если объявлена локальная переменная, то доступ к глобальной переменной с тем же именем закрывается – все действия переменных будут происходить с локальной переменной. 

И, собственно, аргументы функции автоматически становятся локальными переменными. 

А теперь, для самопроверки, я предлагаю вам небольшое задание: попробуйте написать функцию, которая возвращает копию переданного ей объекта. 

Как показывает мой собственный опыт, с первого раза может не получиться, но это вполне возможно (как показывает все тот же опыт). 



В начало страницы



В начало страницы