JavaScript. Подробное руководство, 6-е издание, стр. 98

<b>// локальной переменной этой функции. Кроме того, методы доступа также определяются </b>

<b>// внутри этой функции и потому получают доступ к этой локальной переменной.</b>

<b>// Это означает, что значение доступно только этим двум методам и не может быть </b>

<b>// установлено или изменено иначе, как методом записи, </b>

<b>function addPrivateProperty(o, name, predicate) { </b>

<b>  var value; // Это значение свойства</b>

<b>  // Метод чтения просто возвращает значение. </b>

<b>  о[&quot;get&quot; + name] = function() { return value; };</b>

<b>  // Метод записи сохраняет значение или возбуждает исключение,</b>

<b>  // если функция проверки отвергает это значение. </b>

<b>  o[&quot;set&quot; + name] = function(v) { </b>

<b>    if (predicate &amp;&amp; !predicate(v))</b>

<b>             throw Error(&quot;set&quot; + 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, &quot;Name&quot;, function(x) { return typeof x == &quot;string&quot;; });</b>

<b>o.setName(&quot;Frank&quot;); // Установить значение свойства</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; і &lt; 10; i++) funcs[i] = constfunc(i);</b>

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

<b>funcs[5]() // =&gt; 5</b>

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

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

<b>function constfuncs() { var funcs = []; </b>

<b>  for(var і = 0; і &lt; 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>
Кроме того, информация обо всем этом приводится в справочном разделе.