Мое понимание закрытий - то, что они - по существу функция, которая использует переменную, которую Вы приняли бы, будет вне объема. Я предполагаю, вот пример, который я видел на днях:
function closureMaker(somearg)
{
var local_value = 7;
function funcToReturn(arg1, arg2)
{
return local_value + somearg + arg1 + arg2;
}
return funcToReturn;
}
var myClosure = closureMaker(6); //make the closure
myClosure(2, 3); //using it
Теперь закрытие имеет local_value и даже исходный аргумент, somearg. Но я не добираюсь, почему они полезны. Какой смысл того, чтобы использовать 'свободную' переменную local_value или еще более неизвестный мне, почему Вы использовали бы аргумент функции closureMaking в Вашей функции закрытия?
Я интересуюсь больше тем, как это используется в JavaScript, это используется много для запросов Ajax и объектов?
Я добрался какой. Мне нужно почему.
Одним из наиболее практичных и широко распространенных способов использования замыканий является реализация частных или привилегированных членов , например, например:
function Test (param) {
var secret = 3;
function privateMethod() {
//...
}
this.publicMember = param;
this.privilegedMember = function () {
return secret * param;
};
}
var foo = new Test(10);
foo.privilegedMember(); // 30
foo.secret; // undefined
Модуль шаблон также является хорошим примером, который может использовать тот же принцип, например:
var myModule = (function () {
var obj = {}, privateVariable = 1;
function privateMethod() {
// ...
}
obj.publicProperty = 1;
obj.publicMethod = function () {
// private members available here...
};
return obj;
}());
Обычно в цикле for вы хотите указать номер счетчика.
function addLinks () {
for(var i = 0; i < 5; ++i) {
var link = document.createElement('a');
link.appendChild(document.createTextNode('Link ' + i));
link.i = i;
link.onclick = function() { alert( i ) };
document.body.appendChild(link);
}
}
addLinks();
Когда вы переходите по этим ссылкам, появляется предупреждение 5
, потому что цикл уже выполнен, а i
равно 5
. Мы не «сохраняли» состояние i
во время выполнения цикла for.
Мы можем сделать закрытие, чтобы «сохранить» это состояние:
function addLinks () {
for(var i = 0; i < 5; ++i) {
var link = document.createElement('a');
link.appendChild(document.createTextNode('Link ' + i));
link.i = i;
link.onclick = (function(i) { return function() { alert(i ) } })(i);
document.body.appendChild(link);
}
}
addLinks();
i
привязан к самоисполняющимся анонимным функциям, вызываемым в каждом приращении в нашем цикле. Таким образом, состояние сохраняется, и мы получаем правильный # при тревоге.
Замыкания - это простой способ создания функций, зависящих от параметров. Или, говоря иначе, создать конкретный экземпляр семейства функций (читайте дальше, если это непонятно) в зависимости от некоторого значения времени выполнения.
Javascript позволяет передавать функции как члены первого класса; так, например, вы можете передать функцию, определяющую, как объединить два целых числа, обратившись к ней напрямую.
Однако, идя на шаг дальше, замыкание позволяет создать "персонализированную" версию функции, точное поведение которой зависит от некоторой переменной времени выполнения (но в остальном она соответствует фреймворку).
Например, вот функция, которая позволяет curried добавление:
function getAddNFunction(n)
{
function inner(operand)
{
return n + operand;
}
return inner;
}
Теперь, если вы вызовете getAddNFunction(7)
, вы получите функцию, которая добавляет 7 к аргументу. Если вы вызовете getAddNFunction(42.5)
, вы получите функцию, которая добавляет 42.5 к аргументу.
Надеюсь, этот простой пример проясняет преимущество замыканий; они позволяют встраивать аргументы в функцию во время создания, а не передавать их во время выполнения (в конце концов, вызов getAddNFunction(9)(2)
точно такой же, как вызов 9 + 2
, за исключением того, что два аргумента могут быть предоставлены в разное время).
Например, вы можете захотеть вернуть какую-то сложную функцию разбора XML относительно какого-то корневого элемента; закрытие позволяет вам встроить определение этого корневого элемента в саму функцию, а не зависеть от того, что вызывающая сторона будет иметь к нему доступ всякий раз, когда захочет выполнить функцию.
Пример, который вы рассматриваете, пытается показать вам, как работают замыкания. Я думаю о закрытии как о небольших фрагментах кода, которые вы можете передавать. Замечательно то, что (свободные) переменные в замыкании привязаны к текущей лексической области видимости. Вот почему local_value
сохраняет значение 7
, потому что это то, чем было значение local_value
при создании закрытия.
Javascript реализует замыкания с помощью анонимных функций * , но имейте в виду, что технически это две разные концепции.
В контексте Javascript замыкания (реализованные как анонимные функции) очень полезны, когда вы хотите иметь дело с вещами, которые происходят асинхронно; Хорошим примером являются, как вы заявили, запросы AJAX, в которых вы не можете предсказать, когда вы получите ответ от сервера. В этом случае у вас есть анонимная функция, называемая обратным вызовом , которую вы изначально определяете и передаете при выполнении вызова AJAX. Когда вызов успешно завершается, вызывается ваш обратный вызов для обработки результата. Замыкания приводят к более чистому коду, поскольку вы можете упаковать в них поведение и логику. Это также помогает вам абстрагироваться от поведения наших и разделять проблемы.
Еще одно применение анонимных функций / закрытий - обработка событий. Когда происходит событие, вызывается ваш обработчик событий.
Как я уже упоминал ранее, вы можете абстрагировать поведение и логику и поместить их в закрытие. Но что на самом деле делает закрытие таким мощным, так это контекст . Вы можете настроить поведение закрытия в зависимости от среды, в которой оно было создано. Это делает вашу функцию очень универсальной, потому что вы определяете ее аргументы (которые будут влиять на ее поведение) во время ее создания, а не тогда, когда вы вызываете ее (с явными параметрами) во время выполнения.
Вот хорошая статья о закрытии в Javascript.Он длинный, но информативный:
* Как упоминалось в CMS, именованные функции будут вести себя как анонимные функции, потому что они будут иметь доступ к переменным, которые являются определены в той же лексической области видимости (или что-то еще в цепочке). Это наиболее очевидно в внутренних функциях. Но если задуматься, то же самое происходит с любой функцией; у вас есть доступ к переменным, которые были определены в глобальной области (т. е. глобальным переменным).
Возможно, это не совсем то, что вы ищете, но есть отличная статья о замыканиях для Java (как они должны/могут быть реализованы), в которой также рассматриваются некоторые примеры того, где вы захотите их использовать
В дополнение к вышесказанному закрытие помогает скрыть некоторые детали реализации.
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
alert(Counter.value()); /* Alerts 0 */
Counter.increment();
Counter.increment();
alert(Counter.value()); /* Alerts 2 */
Counter.decrement();
alert(Counter.value()); /* Alerts 1 */
Если вы работаете из объектно-ориентированного мира, замыкания позволяют вам создавать, по сути, частные переменные-члены и методы для ваших объектов:
function Constructor(...) {
var privateVar = value;
function privateFunc() {
}
this.publicFunc = function() {
// public func has access to privateVar and privateFunc, but code outside Constructor does not
}
}