Я знаю, что такое закрытие, но я до сих пор не понимаю, почему (или когда) вы будете использовать их
Мое понимание закрытий заключается в том, что они по сути являются функцией, которая использует переменную, которую вы предположили бы, вне сферы видимости. Наверное, это пример, который я видел на днях:
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 и даже исходный arg, somearg. Но я не понимаю, почему они полезны. Какой смысл использовать "свободную" переменную local_value или даже более неизвестную мне, почему бы вы использовать аргумент функции closMaking в вашей функции закрытия?
Меня больше интересует, как это используется в javascript, много ли используется для запросов и объектов AJAX?
Я получил то, что. Мне нужно, почему.
Ответы
Ответ 1
Одним из наиболее практичных и широко распространенных способов использования закрытий является реализация частных или привилегированных членов, например:
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;
}());
Ответ 2
Обычный прогон - это то, что в цикле 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
привязан к самоисполняющимся анонимным функциям, вызываемым в каждом приращении в нашем цикле. Таким образом, состояние сохраняется, и мы получаем предупреждение в правильном порядке.
Ответ 3
Пример, который вы смотрите, пытается показать вам, как работают замыкания. Я думаю о закрытии, как о небольших фрагментах кода, которые вы можете пройти. Оптимальным является то, что (свободные) переменные в замыкании связаны с текущей лексической областью. Вот почему local_value
сохраняет значение 7
, потому что это значение local_value
было при создании замыкания.
Javascript реализует закрывает через анонимные функции * но имейте в виду, что технически это две отдельные концепции.
В контексте Javascript закрытие (реализовано как анонимные функции) очень полезно, когда вы хотите иметь дело с вещами, которые происходят асинхронно; хорошим примером является, как вы сказали, AJAX-запросы, где вы не можете предсказать, когда вы получите ответ с сервера. В этом случае у вас есть анонимная функция, называемая обратным вызовом, которую вы изначально определяете и передаете, когда вы совершаете вызов AJAX. Когда вызов успешно завершен, ваш обратный вызов вызывается для обработки результата. Закрытие приводит к созданию более чистого кода, так как вы можете встраивать в них поведение и логику. Это также помогает вам абстрагировать поведение наших и отдельных проблем.
Другое использование анонимных функций/закрытий для обработки событий. Когда происходит событие, вызывается ваш обработчик событий.
Как я уже упоминал ранее, вы можете абстрагироваться от поведения и логики и положить его в закрытие. Но то, что действительно делает закрытие настолько мощным, является контекстом. Вы можете настроить поведение своего закрытия, в зависимости от среды, в которой он был создан. Это делает вашу функцию очень универсальной, потому что вы определяете ее аргументы (которые будут влиять на его поведение) во время их создания, а не когда вы вызываете его (с явными параметрами) во время выполнения.
Вот хорошая статья о закрытии в Javascript. Он длинный, но информативный:
* Как упоминалось в CMS, именованные функции будут вести себя как анонимные функции, потому что они будут иметь доступ к переменным, которые определены в той же лексической области (или что-то в цепочке). Это наиболее очевидно во внутренних функциях. Но если вы думаете об этом, то это происходит и для любой функции; у вас есть доступ к переменным, которые были определены в глобальной области (то есть глобальные переменные).
Ответ 4
Это, вероятно, не совсем то, что вы ищете, но есть прекрасная беседа о закрытии Java (как они должны/могут быть реализованы), а также некоторые примеры того, где вы хотели бы их использовать.
http://www.youtube.com/watch?v=0zVizaCOhME
Ответ 5
Закрытие - это простой способ сделать функции, зависящие от параметров. Или, другими словами, создать конкретный экземпляр семейства функций (читайте, если это не понятно) в зависимости от некоторого значения времени выполнения.
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 относительно некоторого корневого элемента; закрытие позволяет вставлять это определение корневого элемента внутри самой функции, а не зависеть от того, кто имеет доступ к нему, когда он хочет выполнить эту функцию.
Ответ 6
Если вы являетесь comnig из мира OO, закрытие позволяет вам создавать то, что является, по существу, частными переменными-членами и методами для ваших объектов:
function Constructor(...) {
var privateVar = value;
function privateFunc() {
}
this.publicFunc = function() {
// public func has access to privateVar and privateFunc, but code outside Constructor does not
}
}
Дуглас Крокфорд и доброта javascript
Ответ 7
В дополнение к закрытию выше помогает скрывать некоторые детали реализации.
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 */
Еще одна хорошая статья
Прочитайте эту статью о шаблоне модуля в javascript, который сильно использует закрытие.