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

<b>  return function() { return counter++; };</b>

<b>}());</b>

Внимательно изучите этот пример, чтобы понять, как он действует. На первый взгляд, первая строка выглядит как инструкция присваивания функции переменной uniquelnteger. Фактически же это определение и вызов функции (как подсказывает открывающая круглая скобка в первой строке), поэтому в действительности переменной uniquelnteger присваивается значение, возвращаемое функцией. Если теперь обратить внимание на тело функции, можно увидеть, что она возвращает другую функцию. Именно этот объект вложенной функции и присваивается переменной uniquelnteger. Вложенная функция имеет доступ к переменным в ее области видимости и может использовать переменную counter, объявленную во внешней функции. После возврата из внешней функции никакой другой программный код не будет иметь доступа к переменной counter: вложенная функция будет обладать исключительным правом доступа к ней.

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

<b>function counter() { var n = 0; </b>

<b>  return {</b>

<b>    count: function() { return n++; }, </b>

<b>    reset: function() { n = 0; }</b>

<b>  };</b>

<b>}</b>

<b>var c = counter(), d = counter(); // Создать два счетчика</b>

<b>c.count()         // =&gt; 0</b>

<b>d.count()         // =&gt; 0: они действуют независимо</b>

<b>с.reset() // методы reset() и count() совместно</b>

<b>// используют одну переменную</b>

<b>c.count() // =&gt; 0: сброс счетчика с</b>

<b>d.count() // =&gt; 1: не оказывает влияния на счетчик d</b>

Функция

<b>counter()</b>
возвращает объект «счетчика». Этот объект имеет два метода:
<b>count(),</b>
возвращающий следующее целое число, и
<b>reset(),</b>
сбрасывающий счетчик в начальное состояние. В первую очередь следует запомнить, что два метода совместно используют одну и ту же частную переменную n. Во-вторых, каждый вызов функции
<b>counter()</b>
создает новую цепочку областей видимости и новую скрытую переменную. То есть, если вызвать функцию
<b>counter()</b>
дважды, она вернет два объекта-счетчика с различными скрытыми переменными. Вызов методов
<b>count()</b>
и
<b>reset()</b>
одного объекта-счетчика не оказывает влияния на другой.

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

<b>counter()</b>
является вариацией примера, представленного в разделе 6.6, но здесь для хранения скрытой информации вместо обычного свойства объекта используются замыкания:

<b>function counter(n) { // Аргумент n функции - скрытая переменная </b>

<b>  return {</b>

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

<b>    get count() { return n++; },</b>

<b>    // Метод записи в свойство не позволяет уменьшать значение n </b>

<b>    set count(m) {</b>

<b>      if (m &gt;= n) </b>

<b>        n = m;</b>

<b>      else throw Error( &quot;значение счетчика нельзя уменьшить&quot;);</b>

<b>    }</b>

<b>  };</b>

<b>}</b>

<b>var с = counter(1000);</b>

<b>с.count // =&gt; 1000</b>

<b>с.count // =&gt; 1001</b>

<b>с.count = 2000</b>

<b>с.count // =&gt; 2000</b>

<b>с.count = 2000 // =&gt; Ошибка!</b>

Обратите внимание, что эта версия функции

<b>counter()</b>
не объявляет локальную переменную. Для сохранения информации она просто использует параметр n, доступный обоим методам доступа к свойству. Это позволяет программе, вызывающей
<b>counter(),</b>
определять начальное значение скрытой переменной.

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

Пример 8.4. Реализация методов доступа к частному свойству с использованием замыканий

<b>// Эта функция добавляет методы доступа к свойству с заданным именем объекта о.</b>

<b>// Методы получают имена вида get&lt;name&gt; и set&lt;name&gt;. Если дополнительно предоставляется </b>

<b>// функция проверки, метод записи будет использовать ее для проверки значения </b>

<b>// перед сохранением. Если функция проверки возвращает false,</b>

<b>// метод записи генерирует исключение.</b>

<b>//</b>

<b>// Необычность такого подхода заключается в том, что значение свойства,</b>

<b>// доступного методам, сохраняется не в виде свойства объекта о, а в виде </b>