scripts

пятница, 23 августа 2013 г.

Немного о JavaScript. Функции. Замыкания.

Понятие замыкания тесно связан с пониманием области видимости. Еще раз отмечу тот факт, что JavaScript не поддерживает области видимости блока, только функции определяют область видимости. Если я внутри функции определю внутреннюю функцию, то это внутренняя функция  будет иметь доступ к параметрам и переменным той функции в которой она определена - это свойство называют замыканием. Замыкания - это сильная сторона JavaScript.
Работая с замыканиями надо быть аккуратным - иначе результат может не оправдать ваших ожиданий. Рассмотрим такой пример: есть отряд курсантов и мы произвели расчет по порядку. То есть первый курсант - "первый", второй - "второй" и т.д. Теперь мы хотим обратиться к курсанту и узнать его порядковый номер.
Создадим функцию stroy().
function stroy() {
  var poryadok = ["первый", "второй", "третий"],
      i,
      kursants = [];
  for (i = 0; i < 3; i++) {
    kursants[i] = function () {
      return poryadok[i];
    };
  }
  return kursants;
}

Теперь мы хотим обратиться к курсанту и он должен сказать свой порядковый номер, что ж попробуем.
var otryad = stroy();
console.log(otryad[2]());

Мы рассчитываем увидеть "третий", но увы получаем
undefined
Хм, не совсем то, что мы ожидали. Давайте разберемся в чем дело и исправим нашу программу. Самый первый вопрос, который приходит в голову, а какое значение имеет переменная i, когда мы возвращаем poryadok[i]. Для отладки закоментируем строку
//return poryadok[]
и напишем
console.log(i)
Теперь видим, что в момент вызова poryadok[i] переменная i равна 3. Получается мы вышли за предел массива и получили вполне заслуженно undefined. Особенность заключается в том, что внутренняя функция при замыкании получает значение переменной внешней функции по ссылке. Получается, что после окончания цикла, переменная i будет иметь значение 3, которое по ссылке и получит внутренняя функция. Есть способ обойти эту особенность и получить нужное поведение. Для этого будем использовать немедленно вызываемую функцию.

function stroy() {
  var poryadok = ["первый", "второй", "третий"],
      i,
      kursants = [];
  for (i = 0; i < 3; i++) {
    kursants[i] = (function (num) {
      return function () {
        return poryadok[num];
      }
    })(i);
  }
  return kursants;
}

var otryad = stroy();

console.log(otryad[2]());

Запустим на исполнение и увидим в результате
"третий"
Вот теперь другое дело. Что ж на этом все. Далее поговорим о прототипах и наследовании.

Комментариев нет:

Отправить комментарий