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

с.count // => 1000

с.count // => 1001

с.count = 2000

с.count // => 2000

с.count = 2000 // => Ошибка!

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

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

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

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

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

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

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

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

//

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

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

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

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

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

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

function addPrivateProperty(o, name, predicate) {

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

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

  о["get" + name] = function() { return value; };

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

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

  o["set" + name] = function(v) {

    if (predicate && !predicate(v))

             throw Error("set" + name + недопустимое значение + v);

    else

      value = v;

  };

}

// Следующий фрагмент демонстрирует работу метода addPrivateProperty().

var о = {}; // Пустой объект

// Добавить к свойству методы доступа с именами getName() и setName()

// Обеспечить допустимость только строковых значений

addPrivateProperty(o, "Name", function(x) { return typeof x == "string"; });

o.setName("Frank"); // Установить значение свойства

console.log(o.getName()); // Получить значение свойства

о.setName(0); // Попробовать установить значение свойства неверного типа

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