Выбрать главу

// Эта функция возвращает функцию, которая всегда возвращает v

function constfunc(v) { return function() { return v; }; }

// Создать массив функций-констант:

var funcs = [];

for(var і = 0; і < 10; i++) funcs[i] = constfunc(i);

// Функция в элементе массива с индексом 5 возвращает 5.

funcs[5]() // => 5

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

// Возвращает массив функций, возвращающих значения 0-9

function constfuncs() { var funcs = [];

  for(var і = 0; і < 10; i++)

    funcs[i] = function() { return i; };

  return funcs;

}

var funcs = constfuncs();

funcs[5]() // Что вернет этот вызов?

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

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

var self = this; // Сохранить значение this в переменной для использования

// во вложенной функции.

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

var outerArguments = arguments; // Сохранить для использования во вложенных функциях

В примере 8.5, далее в этой главе, определяется замыкание, использующее эти приемы для получения доступа к значениям this и arguments внешней функции.

8.7. Свойства и методы функций и конструктор Function

Мы видели, что в JavaScript-программах функции могут использоваться как значения. Оператор typeOf возвращает для функций строку «function», однако в действительности функции в языке JavaScript - это особого рода объекты. А раз функции являются объектами, то они имеют свойства и методы, как любые другие объекты. Существует даже конструктор Function(), который создает новые объекты функций. В следующих подразделах описываются свойства и методы функций, а также конструктор Function(). Кроме того, информация обо всем этом приводится в справочном разделе.

8.7.1. Свойство length

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