<b>// локальной переменной этой функции. Кроме того, методы доступа также определяются </b>
<b>// внутри этой функции и потому получают доступ к этой локальной переменной.</b>
<b>// Это означает, что значение доступно только этим двум методам и не может быть </b>
<b>// установлено или изменено иначе, как методом записи, </b>
<b>function addPrivateProperty(o, name, predicate) { </b>
<b> var value; // Это значение свойства</b>
<b> // Метод чтения просто возвращает значение. </b>
<b> о["get" + name] = function() { return value; };</b>
<b> // Метод записи сохраняет значение или возбуждает исключение,</b>
<b> // если функция проверки отвергает это значение. </b>
<b> o["set" + name] = function(v) { </b>
<b> if (predicate && !predicate(v))</b>
<b> throw Error("set" + name + недопустимое значение + v);</b>
<b> else</b>
<b> value = v;</b>
<b> };</b>
<b>}</b>
<b>// Следующий фрагмент демонстрирует работу метода addPrivateProperty(). </b>
<b>var о = {}; // Пустой объект</b>
<b>// Добавить к свойству методы доступа с именами getName() и setName()</b>
<b>// Обеспечить допустимость только строковых значений</b>
<b>addPrivateProperty(o, "Name", function(x) { return typeof x == "string"; });</b>
<b>o.setName("Frank"); // Установить значение свойства</b>
<b>console.log(o.getName()); // Получить значение свойства</b>
<b>о.setName(0); // Попробовать установить значение свойства неверного типа</b>
Мы увидели несколько примеров, когда замыкания определяются в одной и той же цепочке областей видимости и совместно используют одну локальную пере¬менную или переменные. Важно знать и уметь пользоваться этим приемом, но но менее важно уметь распознавать ситуации, когда замыкания получают перемен¬ную в совместное использование по ошибке. Рассмотрим следующий пример:
<b>// Эта функция возвращает функцию, которая всегда возвращает v </b>
<b>function constfunc(v) { return function() { return v; }; }</b>
<b>// Создать массив функций-констант: </b>
<b>var funcs = [];</b>
<b>for(var і = 0; і < 10; i++) funcs[i] = constfunc(i);</b>
<b>// Функция в элементе массива с индексом 5 возвращает 5. </b>
<b>funcs[5]() // => 5</b>
При создании подобного программного кода, который создает множество замыканий в цикле, часто допускают ошибку, помещая цикл внутрь функции, которая определяет замыкания. Например, взгляните на следующий фрагмент:
<b>// Возвращает массив функций, возвращающих значения 0-9 </b>
<b>function constfuncs() { var funcs = []; </b>
<b> for(var і = 0; і < 10; i++)</b>
<b> funcs[i] = function() { return i; }; </b>
<b> return funcs;</b>
<b>}</b>
<b>var funcs = constfuncs();</b>
<b>funcs[5]() // Что вернет этот вызов?</b>
Функция выше создает 10 замыканий и сохраняет их в массиве. Замыкания образуются в одном и том же вызове функции, поэтому все они получат доступ к переменной і. Когда
<b>constfuncs()</b>
вернет управление, переменная і будет иметь значение 10, и все 10 замыканий будут совместно использовать это значение. Таким образом, все функции в возвращаемом массиве будут возвращать одно и то же значение, что совсем не то, чего мы пытались добиться. Важно помнить, что цепочка областей видимости, связанная с замыканием, не фиксируется. Вложенные функции не создают частные копии области видимости и не фиксируют значения переменных.
Кроме того, при создании замыканий следует помнить, что
<b>this</b>
- это ключевое слово, а не переменная. Как отмечалось выше, каждый вызов функции получает свое значение
<b>this</b>
, и замыкание не имеет доступа к значению
<b>this</b>
внешней функции, если внешняя функция не сохранит его в переменной:
<b>var self = this; // Сохранить значение this в переменной для использования </b>
<b>// во вложенной функции.</b>
То же относится и к объекту
<b>arguments</b>
. Это не ключевое слово, но он автоматически создается при каждом вызове функции. Поскольку замыкания при вызове получают собственный объект
<b>arguments</b>
, они не могут обращаться к массиву аргументов внешней функции, если внешняя функция не сохранит этот массив в переменной с другим именем:
<b>var outerArguments = arguments; // Сохранить для использования во вложенных функциях</b>
В примере 8.5, далее в этой главе, определяется замыкание, использующее эти приемы для получения доступа к значениям
<b>this</b>
и
<b>arguments</b>
внешней функции.
8.7. Свойства и методы функций и конструктор Function
Мы видели, что в JavaScript-программах функции могут использоваться как значения. Оператор
<b>typeOf</b>
возвращает для функций строку «function», однако в действительности функции в языке JavaScript - это особого рода объекты. А раз функции являются объектами, то они имеют свойства и методы, как любые другие объекты. Существует даже конструктор
<b>Function(),</b>
который создает новые объекты функций. В следующих подразделах описываются свойства и методы функций, а также конструктор
<b>Function().</b>
Кроме того, информация обо всем этом приводится в справочном разделе.