Допустим, вам нужна функция, которую можно использовать для возврата уникального значения id, которое будет использоваться при создании новых элементов DOM. Теперь, в чем-то вроде Java, вы можете создать класс с внутренним частным счетчиком, а затем иметь метод, который добавляет счетчик к некоторой строке префикса. Что ж, в Javascript:
var getId = (function() {
var counter = 0;
return function() {
return "prefix" + counter++;
};
})();
Теперь переменная "getId" связана с функцией, которая создана другой функцией и создана таким образом, что у нее есть постоянная переменная для использования между вызовами. Точно так же, если бы я хотел иметь семейство функций "getId" (скажем, по одной для каждого типа элемента DOM, который я мог бы добавить), я мог бы сделать это:
var getIdFunc = function(prefix) {
var counter = 0;
return function() {
return prefix + counter++;
};
};
var getId = {
'div': getIdFunc('div'),
'span': getIdFunc('span'),
'dl': getIdFunc('dl'),
// ...
};
Теперь я могу вызвать getId.div()
, чтобы получить новое значение «id» для нового <div>
. Функция была создана путем вызова функции, которая предоставляет два значения, спрятанных в закрытии: строку префикса (переданную как аргумент) и счетчик (var
, объявленный в области закрытия).
Как только вы привыкнете к нему, он станет настолько гибким и полезным, что вы почувствуете боль, возвращаясь в среду без него.
О, и вот совет, который поможет вам избежать StackOverflow, если вы попробуете это: эта проблема возникает постоянно:
for (var i = 0; i < 10; ++i) {
var id = "foo" + i;
var element = document.getElementById(id);
element.onclick = function() {
alert("hello from element " + i);
};
}
В чем проблема? Ну, переменная «i», на которую ссылается эта функция, - это «i» из области, в которой выполняется этот цикл. Вы заметите, что эта переменная увеличивается в цикле (да, да?). Что ж, каждая из этих маленьких функций, созданных и назначенных в качестве обработчиков событий, будет совместно использовать одну и ту же единственную переменную "i" в области закрытия. Ой! Решение - сделать что-то вроде этого:
for (var i = 0; i < 10; ++i) {
var id = "foo" + i;
var element = document.getElementById(id);
element.onclick = (function(iCopy) {
return function() {
alert("hello from element " + iCopy);
};
})(i);
}
Мы делаем копию внешнего «i» в собственную область замыкания, так что теперь у каждого обработчика событий есть свой собственный!
Подводя итог: техника использования замыканий появляется чертовски много времени, как только вы к ней привыкните. Это не бесплатный билет в новую страну чудес безошибочного программирования; не поймите меня неправильно. Однако это очень полезная и гибкая парадигма.
person
Pointy
schedule
12.04.2010