Javascript.RU

Замыкания

Update: Более новый материал по этой теме находится по адресу https://learn.javascript.ru/functions-closures.

Замыкание - одно из мощных выразительных средств javascript, которым часто пренебрегают, и даже не советуют употреблять.

Действительно, замыкания могут приводить к проблемам. Но на самом деле они очень удобны, просто нужно понимать, что реально происходит.

Если говорить просто, то замыкание - это внутренняя функция. Ведь javascript разрешает создавать функции по ходу выполнения скрипта. И эти функции имеют доступ к переменным внешней функции.

В этом примере создается внутренняя функция func, изнутри которой доступны как локальные переменные, так и переменные внешней функции outer:

function outer() {
	var outerVar;

	var func = function() {
		var innerVar
		...
		x = innerVar + outerVar
	}
	return func
}

Когда заканчивает работать функция outer, внутренняя функция func остается жить, ее можно запускать в другом месте кода.

Получается, что при запуске func используется переменная уже отработавшей функции outer, т.е самим фактом своего существования, func замыкает на себя переменные внешней функции (а точнее - всех внешних функций).

Наиболее часто замыкания применяются для назначения функций-обработчиков событий:

function addHideHandler(sourceId, targetId) {
	var sourceNode = document.getElementById(sourceId)
	var handler = function() {
		var targetNode = document.getElementById(targetId)
		targetNode.style.display = ‘none’
	}
	sourceNode.onclick = handler
}

Эта функция принимает два ID элементов HTML и ставит первому элементу обработчик onclick, который прячет второй элемент.

Т.е,

// при клике на элемент с ID="clickToHide"
// будет спрятан элемент с ID="info"
addHideHandler("clickToHide", "info")

Здесь динамически созданный обработчик события handler использует targetId из внешней функции для доступа к элементу.

.. Если Вы хотите углубиться поглубже и разбираться подольше..

..На самом деле происходящее в интерпретаторе Javascript гораздо сложнее и содержит куда больше деталей, чем здесь описано...

..Но чтобы понять и использовать замыкания, достаточно понять внутренний механизм работы функций, хотя бы и в таком, местами упрощенном виде...

Каждое выполнение функции хранит все переменные в специальном объекте с кодовым именем [[scope]], который нельзя получить в явном виде, но он есть .

Каждый вызов var... - всего лишь создает новое свойство этого объекта, а любое упоминание переменной - первым делом ищется в свойствах этого объекта.

Такова внутренняя структура "области видимости" - это обыкновенный объект. Все изменения локальных переменных являются изменениями свойств этого неявного объекта.

Обычно после того, как функция закончила выполнение, ее область видимости [[scope]], т.е весь набор локальных переменных убивается.

Общий поток выполнения выглядит так:

// функция для примера
function sum(x,y) {
	// неявно создался объект [[scope]]
	...
	// в [[scope]] записалось свойство z
	var z
	// нашли переменную в [[scope]], [[scope]].z = x+y
	z = x+y
	// нашли переменную в [[scope]], return [[scope]].z
	return z

	// функция закончилась,
	// [[scope]] никому больше не нужен и умирает вместе с z
}

Кстати, для кода вне функции(и вообще глобальных переменных) роль объекта-контейнера [[scope]] выполняет объект window.

Когда одна функция создается внутри другой, то ей передается ссылка на объект с локальными переменными [[scope]] внешней функции.

Благодаря существованию этой ссылки, из внутренней функции можно получить переменные внешней функции - через ссылку на ее [[scope]]. Сначала ищем у себя, затем - во внешнем [[scope]] - и так далее по цепочке до самого объекта window.

Замыкание - это когда объект локальных переменных [[scope]] внешней функции остается жить после ее завершения.

Внутренняя функция может обратиться к нему в любой момент и получить переменную внешней функции.

Например, разберем работу функции, которая устанавливает обработчики событий:

function addHideHandler(sourceId, targetId) {
	// создан объект [[scope]] со свойствами sourceId, targetId

	// записать в [[scope]] свойство sourceNode
	var sourceNode = document.getElementById(sourceId)

	// записать в [[scope]] свойство handler
	var handler = function() {
		var targetNode = document.getElementById(targetId)
		targetNode.style.display = ‘none’
	}

	sourceNode.onclick = handler

	// функция закончила выполнение
	// (***) и тут - самое интересное!
}

При запуске функции все происходит стандартно:

  1. создается [[scope]]
  2. туда записываются локальные переменные
  3. внутренняя функция получает ссылку на [[scope]]

Но в самом конце - внутренняя функция присваивается sourceNode.onclick. Внешняя функция закончила свою работу, но внутренняя - может запуститься когда-нибудь потом.

Интерпретатор javascript не проводит анализ - понадобятся ли внутренней функции переменные из внешней, и какие переменные могут быть нужны.

Вместо этого он просто оставляет весь [[scope]] внешней функции в живых.

Чтобы когда внутренняя функция запустится, если она вдруг не найдет какую-либо переменную в своем [[scope]] - она могла обратиться к [[scope]] внешней функции и нашла бы ее там.

Если внешняя функция была создана внутри еще одной (еще более внешней) функции - то в цепочку добавляется еще один консервированный [[scope]] и так - до глобальной области window.

В этом примере внешняя функция makeShout() создает внутреннюю shout().

function makeShout() { // (1)
    var phrase = "Превед!"  // (2)

    var shout = function() {  // (3,4)
        alert(phrase) 
    }
    
    phrase = "Готово!"  // (5)

    return shout
}

shout = makeShout()
// что выдаст?
shout()

Функция shout() на правах внутренней функции имеет доступ к переменной phrase. Какое значение она выведет - первое или второе?

Если неочевидно - перед тем, как читать дальше, попробуйте этот пример запустить.

А вот - подробное описание происходящего в недрах javascript:

  1. Внутри makeShout()
    1. создается [[scope]]
    2. В [[scope]] пишется: phrase="Превед!"
    3. В [[scope]] пишется: shout=..функция..
    4. При создании функция shout получает ссылку на [[scope]] внешней функции
    5. [[scope]].phrase меняется на новое значение "Готово!"
  2. При запуске shout()
    1. Создается свой собственный объект [[scope2]]
    2. Ищется phrase в [[scope2]] - не найден
    3. Ищется phrase в [[scope]] внешней функции - найдено значение "Готово!"
    4. alert("Готово!")

То есть, внутренняя функция получает последнее значение внешних переменных.

Замыкание позволяет создать функцию суммирования, которая работает вот так:

sum(a)(b) = a+b

// например
sum(1)(3) = 4

Да, именно так: скобки - не опечатки.

А вот и сама функция sum:

function sum(a) {
  return function(b) {
    return a+b
  }
}

Функция addEvents принимает массив div'ов и ставит каждому вывод своего номера на onclick.

С вопроса "Почему это не работает?" люди обычно начинают изучение замыканий.

function addEvents(divs) {
	for(var i=0; i<divs.length; i++) {	
		divs[i].innerHTML = i
		divs[i].onclick = function() { alert(i) }
	}
}

Для тестового примера сделаем 10 разноцветных нумерованных div'ов с разными цветами:

function makeDivs(parentId) {
	for (var i=0;i<10;i++) {
		var j = 9-i
		var div = document.createElement('div')
		div.style.backgroundColor = '#'+i+i+j+j+j+i
		div.className="closure-div"
		div.style.color = '#'+j+j+i+i+i+j
		document.getElementById(parentId).appendChild(div)
	}
}

Кнопка ниже создаст 10 дивов и вызовет для них addEvents

Если Вы покликаете на div'ы - они все выдают одинаковый alert.

Такой глюк возник из-за того, что все функции div[i].onclick получают значение i из одного на всех [[scope]] внешней функции. А это значение ([[scope]].i) на момент активации onclick-обработчика равно 10 (цикл завершился как только i==10).

Чтобы все было в порядке, в таких случаях применяют специальный прием - выделение [[scope]]. Следующая функция работает правильно. В ней все то же самое, кроме div.onclick.

function addEvents2(divs) {
	for(var i=0; i<divs.length; i++) {	
		divs[i].innerHTML = i
		divs[i].onclick = function(x) {
			return function() { alert(x) }
		}(i)
	}
}

Теперь все должно быть в порядке - каждый div дает alert на свой номер.

Для присваивания div.onclick запускается временная функция function(x) {..}, принимающая аргумент x и возвращающая обработчик, который берет x из [[scope]] этой временной функции.

Запись function(x) {..} используется для создания функции, и тут же (i) - для запуска с аргументом i.

Вообще, javascript очень удобный в этом смысле язык. Допускает любые конструкции, например, вместо последовательных вызовов:

var f = function(a) { return [0, a, 2*a] }
var t = f(1)
var result = t[2] // 2

можно в одну строчку создать и тут же вызвать функцию и тут же получить 2й элемент массива:

var result = function(a){ return [0,a,2*a] }(1)[2]

Временная функция function(x) {..} заканчивает работать тут же, оставляя в своем [[scope]] правильное значение x, равное текущей переменной i цикла.

Когда обработчик активизируется - alert возьмет из [[scope]] ближайшей внешней функциии правильное значение x.

По идее, этих примеров должно хватать для понимания и практического использования замыканий.

Также про замыкания можно почитать, например в cтатье http://www.jibbering.com/faq/faq_notes/closures.html

Конечно, разобрать происходящее во всех деталях позволит стандарт языка ECMA-262.


Автор: Гость (не зарегистрирован), дата: 14 июля, 2008 - 05:09
#permalink

На моем браузере вывод "makeDivs + addEvents" и "makeDivs + новая функция" отображаются одинаково.


Автор: Илья Кантор, дата: 14 июля, 2008 - 21:08
#permalink

Да, makeDivs должны отображаться одинаково. Но работают по-разному.


Автор: Sirius (не зарегистрирован), дата: 14 августа, 2008 - 20:11
#permalink

Для общего развития очень даже интересно.
Сам занимаюсь сбором информации по теме web-программирования.
Кстати, у меня есть тоже немало интересных на мой взгляд статей и примеров по javaScript
Все-таки без JavaScript вэб был бы очень скучным


Автор: Гость (не зарегистрирован), дата: 17 сентября, 2008 - 18:27
#permalink

Расскажите плз. про последниий пример поподробнее, я ничего не понял
>>alert( function a(){ return [5] }()[0] ) // => выведет 5
и чуть выше тоже


Автор: Илья Кантор, дата: 18 сентября, 2008 - 11:57
#permalink

Ок, спасибо. Сделал эту часть подробнее.


Автор: twolf, дата: 10 октября, 2008 - 17:53
#permalink

Отличная статья. спасибо


Автор: blade-mscl, дата: 14 октября, 2008 - 00:01
#permalink

спасибо. была проблема. разобрался.


Автор: Павел Мартемьянов (не зарегистрирован), дата: 15 ноября, 2008 - 23:21
#permalink

Спасибо за статью.
Возник вопрос по работе с локальными переменными в таких случаях в отладчике Firebug.

В этом примере

var xx = 20;
(function(){
var xx = 10;
func = function(){
alert(xx);
}
})();
func();

отладчик Firebug при вызове функции func()
показывает что xx = 20, хотя alert() выводит правильное значение 10.

Как следить за переменной из [[scope]] функции func ??


Автор: Илья Кантор, дата: 24 ноября, 2008 - 14:50
#permalink

В вашем коде нет явного вызова отладчика командой debugger. Вставьте ее, чтобы понимать точное место вызова в коде.


Автор: Тамара (не зарегистрирован), дата: 24 ноября, 2008 - 02:17
#permalink

Спасибо за столь подробное объянение


Автор: grang (не зарегистрирован), дата: 7 декабря, 2008 - 13:27
#permalink

Отличная статья, спасибо огромное!


Автор: Гаврила (не зарегистрирован), дата: 7 декабря, 2008 - 13:29
#permalink

Молодцы спасибо за статью!


Автор: flaer (не зарегистрирован), дата: 7 декабря, 2008 - 13:31
#permalink

Спс... очень признателен!


Автор: zaremba (не зарегистрирован), дата: 14 декабря, 2008 - 03:49
#permalink

Не лишне было бы упомянуть, что замыкания можно организовать и с использованием неанонимных внутренних функций.


Автор: Dicot (не зарегистрирован), дата: 14 января, 2009 - 13:53
#permalink

Очень похоже, что [[scope]].[[prototype]] вложенной функции == [[scope]] внешней. Это действительно так, или я ошибаюсь?


Автор: Илья Кантор, дата: 20 января, 2009 - 07:53
#permalink

Речь идет просто об иерархии, в чем-то аналогичной наследованию через прототипы.

Однако, насколько я понимаю - из стандарта (http://javascript.ru/ecma/part10#a-10.1.4) не следует, что у [[scope]] есть свойство [[prototype]]. Просто сказано, что [[scope]]'ы формируют иерархию..


Автор: maicroft (не зарегистрирован), дата: 15 февраля, 2009 - 18:48
#permalink

Спасибо. Очень интересно и понятно!


Автор: Гость (не зарегистрирован), дата: 26 февраля, 2009 - 18:28
#permalink

Спасибо за столь подробное объянение


Автор: Гость (не зарегистрирован), дата: 22 апреля, 2009 - 00:58
#permalink

Отлично!


Автор: Гость (не зарегистрирован), дата: 4 июня, 2009 - 17:55
#permalink

хорошая статья) первый раз вижу такое на русском языке)


Автор: dzyanis, дата: 8 июня, 2009 - 19:20
#permalink

Спасибо! На русском аналогов не видел, по моему даже на википедии нет!


Автор: Митяй (не зарегистрирован), дата: 23 июля, 2009 - 08:05
#permalink

Отличная статья, материал не то чтобы сложный, но везде он как-то через назад описан, а тут - ясно и четко.
Кстати, в варианте "Веселой функции"
sum(1)(3) = 4
я бы посоветовал вычитание
sub(7)(8) = -1
гораздо нагляднее, что в какую очередь вызывается.
ИМХО.


Автор: porqz (не зарегистрирован), дата: 4 августа, 2009 - 16:49
#permalink

Скажите, пожалуйста, а как оградить переменные во внешней фунции от внутренней? Сталкнулся с этой проблемой, когда писал рекурсивную функцию. Заранее спасибо.


Автор: Леонид Евстигнеев, дата: 4 августа, 2009 - 18:56
#permalink

Подозреваю, что вам поможет слово var.


Автор: Рюкан (не зарегистрирован), дата: 9 октября, 2009 - 15:00
#permalink

Спасибо! очень толково и понятно освящен такой сложный для меня вопрос)


Автор: Девушка (не зарегистрирован), дата: 19 октября, 2009 - 18:41
#permalink

Честно сказать, у меня брызнули слезы из глаз.. Я так долго пыталась понять, как работает Javascript, а тут прочитала - и за 5 минут все улеглось по полочкам. Огромное спасибо!


Автор: Гость (не зарегистрирован), дата: 9 ноября, 2009 - 10:19
#permalink

знаете, всё это, конечно, интересно и всё такое, но я бы попросил цвет скобок из зелёного сделать каким нибудь другим. например, синим или оранжевым, ибо зелёный на белом видно плохо и, чтоб отличить фигурную скобку от круглой, приходится глаза ломать... спасибо.
з.ы. ещё их можно обозначить полужирным шрифтом.


Автор: Shivo (не зарегистрирован), дата: 14 декабря, 2009 - 12:44
#permalink

Спасибо за очень хорошую статью.


Автор: Lexis (не зарегистрирован), дата: 25 декабря, 2009 - 11:31
#permalink

Добрый день. У меня возник следующий вопрос. Что и в каких scope происходит со свойством x в данном примере:

var x = 10;
var f = function() {
  if (x == 10) {
    var x = 20;
  }
  alert(x);
}
f();

Почему в результате я получаю undefined?


Автор: Azadi, дата: 3 января, 2010 - 19:10
#permalink
var x = 10;
var f = function() {
	if (x == 10) {
	x = 20;
	}
return alert(x);
}
f();

Вот это работает как надо, вот только почему не работает при var x=20; мне непонятно... Как вариант, некорректная запись условия. Надо копать мануал.


Автор: B@rmaley.e><e (не зарегистрирован), дата: 3 января, 2010 - 21:16
#permalink

Потому что используя var x Вы объявляете локальную переменную x. Соответственно, она не существует, пока не будет инициализирована. А для ее инициализации должно выполнится условие, т.е. ее значение должно быть = 10.

var x = 10;
var f = function() { // тут x  - локальная, x = undefined
    if (x == 10) { // тут x до сих пор undefined
    var x = 20; // тут x стало бы 20, но эта ветвь никогда не выполнится
    }
return alert(x);
}
f();

Автор: WalterScott, дата: 27 января, 2010 - 16:03
#permalink

Я думаю, x undefined, потому-что в месте вызова alert(x) есть две переменные x и интерпретатор не может определить, к какой из них он должен обратиться.


Автор: Мараторий, дата: 28 января, 2010 - 07:56
#permalink

WalterScott, вы думаете не правильно. Еще раз внимательно прочтите статью и все станет понятно. B@rmaley.e><e все правильно написал выше.
Не забывайте, что интерпретатор проходится по скрипту дважды:
1. сначала собирает данные о локальных переменных (ищет var) и засовывает их в [[scope]]
2. потом начинает исполнять.


Автор: Gozar, дата: 26 февраля, 2010 - 20:01
#permalink

B@rmaley.e>e

Соответственно, она не существует, пока не будет инициализирована

не совсем так, вернее вот так:

При входе в контекст исполнения создаётся свойство VO с именем переменной, и значением undefined

http://javascript.ru/blog/Dmitry-A.-Soshnikov/Tonkosti-ECMA-262-3.-CHast-2.-Obekt-peremennyh.#obekt-peremennyh-v-kontekste-funkcii

Поэтому Ваши слова в виде:

x = undefined

больше отражают суть.


Автор: AndreyV (не зарегистрирован), дата: 27 января, 2011 - 11:46
#permalink

Одно непонятно - почему переменная x не инициализирована? Ведь при её объявлении через var в самом начале кода она сразу же и инициализируется значением 10


Автор: Goodfella, дата: 8 марта, 2011 - 14:29
#permalink

По всей вероятности, интерпретатор добавил к данному объекту вызова свойство "x" со значением "undefined", всему виной инструкция:

if (x == 10) {
    var x = 20;
}

А точнее оператор "var". И не важно, где он находиться в коде функции, в этой области видимости "x" везде равен "undefined" (пока не присвоено другое значение, разумеется), если убрать "var" - код работает, но меняется значение глобальной переменной.
А вообще, рекомендую почитать раздел "4.3.1. Отсутствие блочной области видимости" в книге Флэнагана, там как-раз рассматривается этот вопрос.


Автор: gobwas (не зарегистрирован), дата: 10 марта, 2011 - 16:36
#permalink

Спасибо за ссылку на 4.3.1 - все сразу встало на свои места =)


Автор: I Владимир (не зарегистрирован), дата: 13 июля, 2012 - 07:01
#permalink

Скорее всего из-за того, что var x=20; интерпретатор создаёт раньше чем происходит сравнение. Интерпретатору пофигу в какой части функции вы объявите переменную scope всё равно приклеивает к этой функции.


Автор: Гость (не зарегистрирован), дата: 6 октября, 2012 - 00:30
#permalink

покажу сказанное:

  1. var x = 10;
  2. alert("x = " + x + " - он не 'undefined'!");
  3. var f = function() {
  4. if (x == 10) { // x со значением "undefined", потому что имеется в виду
  5. var x = 20; // этот х, если его имя изменить на y
  6. }
  7. alert(x); // это будет работать
  8. }
  9. f();

Автор: josser, дата: 31 октября, 2012 - 12:20
#permalink

Ответ через 3 года )

Когда интерпретатор начинает выполнять функцию f он находит все записи var и создает соответствующие переменные но присваивает в них значение undefined.

Далее, когда он перейдет уже непосредственно к выполнению кода значения установятся. Но поскольку x=undefined условие x==10 не выполнится, и значение не установится.


Автор: Гость (не зарегистрирован), дата: 28 марта, 2014 - 19:33
#permalink

потому что интерпретатор выносит имена перемененных и функций в самый верх,
а только потом начинает выполнять код. Соответственно при сравнении (x == 10) значение берется из переменной х которая еще не инициализирована.

var x = 10;
var f = function () {
var x;
if (x == 10) { // x=undefined
x = 20;
}
alert(x);
}
f();


Автор: Yuriy Zaletskyy (не зарегистрирован), дата: 28 января, 2010 - 14:28
#permalink

Как вы отнесетесь, если я сделаю перевод вашей статьи на английский язык с указанием оригинала, т.е. вашей статьи?


Автор: просто гость (не зарегистрирован), дата: 16 апреля, 2010 - 23:42
#permalink

Вопрос про конструкцию:
Что происходит "внутри" когда используются круглые скобки ( … )?
Иллюстрация:

(function a(b){alert(b)}(1)); //1
function a(b){alert(b)}(1); //ничего
(function (){alert(1)}()); //1
function (){alert(1)}(); //syntax error

Автор: Гость (не зарегистрирован), дата: 8 июля, 2010 - 16:11
#permalink

а эта запись о чем говорит fn(p)(p)

P = function(){}
   fn(p)(p) = function(){}

Автор: B@rmaley.e><e, дата: 8 июля, 2010 - 16:53
#permalink

Ни о чем, это вообще exception.


Автор: dekkard (не зарегистрирован), дата: 19 мая, 2010 - 09:43
#permalink

отличная статья!
предельно понятное изложение сути


Автор: Omnes Omnibus (не зарегистрирован), дата: 27 мая, 2010 - 18:27
#permalink

спасибо большое)
все вроде понятно особенно со [[scope]], но вот "забавный" пример я вообще понять не могу! Не могли бы Вы его объяснить... спасибо


Автор: Glazzz (не зарегистрирован), дата: 31 мая, 2010 - 13:26
#permalink

Добрый день!
Спасибо за статью, очень понятно и доступно!

У меня есть вопрос, не омгут ли замыкания вызывать memory leaks?

Например при создании обработчиков событий, когда и сам элемент ДОМ (например див в вашем примере) попадает в [[SCOPE]] и обработчик его события также держит ссылку на тот же [[SCOPE]].
Что произойдет, если например ДИВ будет удален из ДОМ модели?


Автор: Гость (не зарегистрирован), дата: 30 марта, 2012 - 15:14
#permalink

Не просто могут но и вызывают утечки памяти! учитывая что юзается жабаскрипт столь массово и при этом столь гм, ...не слишком чтобы высокими программистами-профи... что надеяться на безошибочное и лишь к месту НЕ употребление var -- на это просто-таки надеяться никак не приходится... Sad


Автор: jegor (не зарегистрирован), дата: 15 июня, 2010 - 02:04
#permalink

Спасибо огромное! Уникальная статья на русском.
Обязательно рекомендую к прочтению!

Вопрос: значит "замыкание" - это closure. А что такое enclosure?


Автор: Гость (не зарегистрирован), дата: 2 июля, 2010 - 14:31
#permalink

Здравствуйте.
function outer() {
02 var outerVar;
03
04 var func = function() {
05 var innerVar
06 ...
07 x = innerVar + outerVar
08 }
09 return func
10 }
Можно ли возвращать переменную func без ()? У меня работает только так return func().
Может, я что-то не учла? Тогда что?


Автор: Гость (не зарегистрирован), дата: 2 июля, 2010 - 14:33
#permalink

Это в самом верху страницы


Автор: DeLight (не зарегистрирован), дата: 22 июля, 2010 - 13:19
#permalink

интересно вот что. почему замыкания не работают с функциями создаваемыми через new Function()?

var outer = function() {
var local = "works";
var inner = new Function("alert(local);");
return inner;
};
outer()();

ReferenceError: loc is not defined.

[[scope]] не передается? или все-таки поиск имени local не так просто ведется?


Автор: DeLight (не зарегистрирован), дата: 22 июля, 2010 - 13:20
#permalink

сорри, local в тексте ошибки вместо loc.


Автор: DeLight (не зарегистрирован), дата: 22 июля, 2010 - 13:22
#permalink

отвечу сам на свой вопрос:
"... [[Scope]] property of functions created via the Function constructor contains always only the global object".
http://dmitrysoshnikov.com/ecmascript/chapter-4-scope-chain/


Автор: Керин (не зарегистрирован), дата: 27 августа, 2010 - 12:17
#permalink

я не очень понял, считал что свойствами window становятся только объявленные вне функции глобальные переменные (без var). из статьи же будто бы следует, что свойствами window становятся все переменные, объявленные вне функции


Автор: Гость (не зарегистрирован), дата: 5 апреля, 2011 - 11:32
#permalink

Для window все переменные локальны, что с var, что без. И это в общем то логично.


Автор: Гость (не зарегистрирован), дата: 27 августа, 2010 - 12:22
#permalink

если я переменную объявляю вне функции, но с var, то она остается глобальной или нет?


Автор: _Serg (не зарегистрирован), дата: 30 августа, 2010 - 15:44
#permalink

становится, попробуй написать вне функции var p=12; а потом где-нибудь alert(window.p) или alert(window['p'])


Автор: Гость (не зарегистрирован), дата: 7 октября, 2010 - 23:37
#permalink

Когда заканчивает работать функция outer, внутренняя функция func остается жить, ее можно запускать в другом месте кода. А вот такой вопрос: func остается в памяти только если ссылку на нее мы сохранили в глобальной переменной или даже если мы объявили внутреннюю функцию и не возвратили(присвоили) глобальной переменной ??


Автор: Гость (не зарегистрирован), дата: 13 октября, 2010 - 08:54
#permalink

Ну как я понимаю, если мы ссылку не сохранили, то объект функция уничтожится после того, как отработает внешняя функция.


Автор: Гость (не зарегистрирован), дата: 27 октября, 2010 - 15:03
#permalink

Правильно ли я понимаю, что в "Забавном примере" sum(a)(b) = a+b, мы можем обращаться к функции как sum(1)(2), использовать вторые скобки с параметром, потому что когда программа заходит в функцию sum(a) {... создается контекст исполнения, функция выполняется и при попадании на строчку return она должна выйти из функции, но перед этим создает ещё один контекст выполнения, так как там находится функция, после чего возвращает это значение. А это значение - ссылка на функцию, в результате чего получается как бы стандартная запись myFunc(b) (название функции в данном случае условное)?

Если мы не возвращаем функцию, но у нас есть различные функции внутри функции, то никакого замыкания не происходит?


Автор: B@rmaley.e><e, дата: 27 октября, 2010 - 22:58
#permalink

Замыкание происходит вне зависимости от того, что Вы возвращаете.

function sum(a) {
  sum.b = function(b) {
    return a+b
  };
  return 5;
};
alert(sum(3)); // set a to 3
alert(sum.b(7)); // call b, 7 + 3 = 10

sum(3); // set a to 5
sum(21); // set a to 21
alert(sum.b(17)); // call b, 17 + 21 = 38

Оно происходит как раз в том случае, если Вы объявляете функцию внутри функции.


Автор: Гость (не зарегистрирован), дата: 28 октября, 2010 - 09:30
#permalink

Тогда получается, что можно обращаться sum(a)(b) (из Забавного примера), потому что мы возвращаем функцию. А замыкание может быть не только при возвращении функции, главное, чтобы была объявлена внутренняя функция, из-за чего создастся Scope с теми параметрами, которые были в функции внешней и вызывать потом внутреннюю функцию с нужными параметрами, в итоге внутренняя функция будет обладать параметрами внешней. Это и есть замыкание? Если так, то какое-то странное название, потому что создается Область видимости для функции, которая видит все Области видимости вплоть до Глобальной области видимости.


Автор: B@rmaley.e><e, дата: 28 октября, 2010 - 13:16
#permalink

Да, так оно и есть. Ну а название как название, по-моему. Никто же не жалуется, что инкапсуляция инкапсуляцией называется.


Автор: cmygeHm, дата: 11 мая, 2011 - 11:00
#permalink

в десятой строчке только не понятно почему а сетится в пять, а не в три...


Автор: Гость (не зарегистрирован), дата: 8 ноября, 2010 - 22:58
#permalink

Еще скажите, что все что здесь описывается это хорошо. Статья годная, спору нет. А вот такие тонкости на любителя, не хочу писать на JavaScript сложные программы.


Автор: B@rmaley.e><e, дата: 9 ноября, 2010 - 00:12
#permalink

Такие тонкости встречаются в JS сплошь и рядом. Любой разработчик среднего уровня должен их знать.


Автор: Гость (не зарегистрирован), дата: 9 ноября, 2010 - 00:16
#permalink

У меня друг на работе пишет для гугл мапс маплеты на javascipt вплоть до вращения divов, так вот ниразу не сталкивался с такими проблемами, ни он ни я, когда писали разного рода приложения, если нет классов и объектов, так и не надо оперировать этими терминами и что-то выдумывать.


Автор: Гость (не зарегистрирован), дата: 9 ноября, 2010 - 00:19
#permalink

Вложенная функция не должна вообще получать доступ к переменным внешней функции если она уже закончила свою работу, этот scope должен уже улететь на фиг. А те переменные должны быть ==null


Автор: Гость (не зарегистрирован), дата: 24 января, 2011 - 01:51
#permalink

Воистину, нечего ответить, кроме, разве что, замечания по поводу того, что лечить мертвых - занятие более перспективное.


Автор: Den Sandman (не зарегистрирован), дата: 1 декабря, 2010 - 02:22
#permalink

Реально спасибо, всё очень просто, понятно и полезно... как, впрочем, и все статьи на этом сайте!


Автор: сочи (не зарегистрирован), дата: 24 января, 2011 - 18:39
#permalink

привет, Есть сайт на интересующую Вас тему.


Автор: Гость (не зарегистрирован), дата: 14 февраля, 2011 - 00:36
#permalink

Где указано количество дивов?


Автор: sky, дата: 20 апреля, 2011 - 13:50
#permalink

Илья, спасибо, статья хорошая.
Из логики приведенных определений, в статье значит ли, что всегда происходит замыкание, будь-то хоть просто объявленная функция?
Или будь то просто вложенные ф-и в которых не происходит оперирования никакими переменными?

Например:

function funcName() {
}
/* тут есть замыкание?, ведь в ф-ии funcName есть доступ к scope (которым явл. window) и интерпретатор не проводит анализ - понадобятся ли внутренней функции переменные ? */ 

function makefunc(x) {
    return function() {    }
}
/* тут тоже замыкание? ведь интерпретатор не проводит анализ - понадобятся ли внутренней функции переменные, а значит их вообще может не быть? */

Автор: sky, дата: 20 апреля, 2011 - 14:16
#permalink

Еще вопрос. Уточните пожалуйста для ясности восприятия термина замыкание, что на чем замыкается?


Автор: bolgovr, дата: 21 сентября, 2011 - 10:42
#permalink

Классическое замыкание выглядит примерно так:

function fn(x){
  var x = x;
  return function(y){
    return x+y;
  }
}
var test = fn(5);
alert(test(5)); // выведет 10
alert(test(10)); //выведет 15

В этом примере возвращаемая внутренняя функция "замыкает" в себе ссылки на переменные внешней функции. При этом переменная x существует только в области видимости функции fn (не в глобальной области), но возвращаемая анонимная функция продолжает иметь к ним доступ.


Автор: melky, дата: 21 сентября, 2011 - 22:38
#permalink

поведаю, это каррингом называется


Автор: bolgovr, дата: 22 сентября, 2011 - 02:02
#permalink

Спасибо что просветили, но общего смысла это не отменяет. Специально для Вас могу привести вот такой пример:

function counter(){
    var cnt = 0;
    return function(){
        return ++cnt;
    }
}
var test = counter();
alert(test()); //1 
alert(test()); //2

Надеюсь отсутствие карринга сделает этот пример больше похожим на замыкание в Ваших глазах. И на будущее - в JavaScript каррирование это всегда замыкание, но замыкание не всегда каррирование.


Автор: melky, дата: 22 сентября, 2011 - 07:43
#permalink

я знаю, что это такое, и могу отличить одно от другого. мне можете не обьяснять


Автор: Sweet, дата: 23 сентября, 2011 - 12:05
#permalink

bolgovr, вам бы самому основы подъучить;)

function fn(x){
  var x = x; // абсолютно бессмысленная строчка

Если что, оператор var тут игнорируется, а переменной x присвытвается значение переменной x.


Автор: bolgovr, дата: 24 сентября, 2011 - 11:40
#permalink

Цель комментариев на этой странице - писать максимально осмысленный код для интерпретатора или писать максимально понятный человеку код, который раскрывает суть вопроса(псевдокод который работает)? С основами JavaScript я знаком, спасибо за беспокойство. У меня к Вам один вопрос - если Вы так хорошо знаете основы, то почему не потрудились сами ответить на вопрос человека "правильным" кодом?


Автор: Гость (не зарегистрирован), дата: 6 августа, 2011 - 16:21
#permalink

Статья интересная. Хотя я пишу несколько лет, и были довольно лсожные проекты, однако всегда обходился без замыкания.
Не могли бы всё же сказать, где и для чего их необходимо испльзовть, пример задачи которая решается при помощи замыкания, и которую тяжело/невозможно/с_трудно_понятным_громоздким_кодом нельзя решить без замыканий?

Вещь коненчо инетресная, но вот никак не могу понять "а нафига?!".
Спасибо.


Автор: B@rmaley.e><e, дата: 6 августа, 2011 - 21:55
#permalink

Есть много массивов из (пар некоторое значение, DOM узел). Назначить каждому узлу обработчик определенного события, внутри которого это некоторое значение просто выводится.


Автор: bolgovr, дата: 21 сентября, 2011 - 12:31
#permalink

замыкания можно использовать для каких-либо сложных расчетов, которые должны выполняться только один раз. Пример:

function hard(){ return 10}; //тут какие-то сложные вычисления

var test = function(){
    var x = hard(); //локальной переменной x присваивается результат выполнения функции hard
    return function(y){ // возвращаем анонимную функцию которая использует переменную x
        return x*y;
    }
}(); //выполняем первую функцию, чтобы переменная x сразу имела результат, а переменная test имела значение функции замыкания использующего x

alert(test(5)); // выполняется внутренняя анонимная функция которая имеет доступ к уже готовому результату вычислений x = hard(). Результат = 50

Замыкания делают код чище и безопасней, так как хранимые переменные хранятся во внутреннем scope родительской функции(а не в глобальном), и доступ к ним имеет только возвращаемая функция. Вот еще пример, более простой:

function FormatCurrency(currencyName){
   var currency = currencyName;
    return function(price){
       return price+' '+currency;
   }
}
var roublesFormatter = new FormatCurrency('руб.'); //это важно создавать объект через "new" чтобы внутренняя переменная currency не перезаписалась, а создалась заново.
var dollarFormatter = new FormatCurrency('$');
alert(roublesFormatter(15)); // выведет "15 руб."
alert(dollarFormatter(15)); // выведет "15 $"

Автор: Гость (не зарегистрирован), дата: 29 марта, 2013 - 03:26
#permalink

Нет никакой необходимости создавать новые экземпляры класса FormatCurrency.
Без new можно спокойно обойтись, поскольку переменная currency не является статическим свойством конструктора. Рекомендую проверить работу кода, удалив дескриптор new.


Автор: AndreyV (не зарегистрирован), дата: 2 марта, 2012 - 20:47
#permalink

Насколько я знаю, замыкания очень удобны для разных паттернов проектирования. То есть именно для организации сложного кода, а не для решения какой-то тривиальной задачи.


Автор: Гость (не зарегистрирован), дата: 12 октября, 2011 - 19:39
#permalink

Комраты есть вопрос, предвосхищая комментарии напишу: я три раза внимательно прочитал статью. Но так и не понял решения для моего вопроса. Изучаю работу с пространством имен, создаю свои методы и т.д. Но вот застрял при обращении к методу он мне возвращает значения которые я записал в someTab, и тут же вывожу в консоль чтобы посмотреть, что получилось - все нормально работает, но во второй раз в консоли он нам говорит, что переменная не определена. Почему это происходит я вроде как уже начал понимать. Но как это исправить хоть убейте не пойму. Уже мозг кипит потихоньку.

Почему сюда а не на форум потому что это наиболее похоже на проблемы затронутые в статье.

var Namespace = {};
  
Namespace = function() {
  this.doSom = function{...};
};

onload = function() {
  var nameSpaceObj = new Namespace();

  var getSom = nameSpaceObj.doSom({
    url:'country.xml',
    success:function(data){
      someTab = data;
      console.log(someTab);
    }
  });
  console.log(someTab);
};

Автор: Гость (не зарегистрирован), дата: 13 октября, 2011 - 12:21
#permalink

Извните разобрался!

Оказывается проблема не втом что переменная находится не в той области видимости а в том что просто console.log глобальной переменной выводится первым:) а та переменная все таки находитя там где и должна быть - в памяти.


Автор: Гость (не зарегистрирован), дата: 19 октября, 2011 - 15:56
#permalink

А если в предыдущем примере написать:

var roublesFormatter = FormatCurrency('руб.');
var dollarFormatter = FormatCurrency('$');

т.е. без new, то при втором вызове FormatCurrency интерпретатор будет искать старую область видимости? - т.е. тот объект scope, который остался висеть в памяти?


Автор: TiSsus (не зарегистрирован), дата: 4 января, 2012 - 03:04
#permalink

Здравствуйте!
Добавьте пожалуйста в статью явное указание, что аргументы функции также записываются в [[scope]]. (У меня по крайней мере записываются


Автор: eT (не зарегистрирован), дата: 18 января, 2012 - 04:53
#permalink


function addEvents2(divs) {
for(var i=0; i
разве так:

function addEvents2(divs) {
for(var i=0; i
не будет работать как ожидается?


Автор: eT (не зарегистрирован), дата: 18 января, 2012 - 04:55
#permalink
function addEvents2(divs) {
	for(var i=0; i<divs.length; i++) {	
		divs[i].innerHTML = i
		divs[i].onclick = function(x) {
			return function() { alert(x) }
		}(i)
	}
}

разве так:

function addEvents2(divs) {
	for(var i=0; i<divs.length; i++) {	
		divs[i].innerHTML = i
		divs[i].onclick = function(x){ alert(x) }(i)
	}
}

не будет работать как ожидается?


Автор: Гость (не зарегистрирован), дата: 4 февраля, 2012 - 05:35
#permalink

не будет
т.к. это будет вызовом функции, а не ее присвоением
первый вариант возвращает функцию которая создается функцией
в вашем варианте просто вызовется функция, а в onclick попадет undefined


Автор: mj4444 (не зарегистрирован), дата: 15 февраля, 2012 - 15:08
#permalink

самая лучшая статья из всех что я видел за много лет на эту тему...


Автор: Гость (не зарегистрирован), дата: 23 марта, 2012 - 16:45
#permalink

Автор: Гость (не зарегистрирован), дата: 23 марта, 2012 - 16:46
#permalink


Автор: Johnny_D, дата: 5 апреля, 2012 - 01:00
#permalink

Пора бы уже комменты прятать в AJAX загрузчик, 90% инфы на странице бесполезные комменты.


Автор: Гость (не зарегистрирован), дата: 7 мая, 2012 - 22:00
#permalink
function addEvents2(divs) {
    for(var i=0; i<divs.length; i++) {  
        divs[i].innerHTML = i
        divs[i].onclick = function(x) {
            return function() { alert(x) }
        }(i) // что это ? что делает ?
    }
}

Автор: Гость (не зарегистрирован), дата: 20 мая, 2012 - 18:40
#permalink

вызывает безымянную функцию function(x) с параметром x = i


Автор: Гость (не зарегистрирован), дата: 6 июня, 2012 - 10:29
#permalink

Очень интересно узнать, когда использование замыкания - вреднО.


Автор: Yunda, дата: 22 июля, 2012 - 01:57
#permalink

Илья, смотри. Я хочу чтобы моя функция запоминала плейсхолдер и потом ставила его обратно если ничего не поменялось. Но что-то не работает с этими замыканиями. Либо я не правильно понял. Помоги

dominos.clearPlaceholder = function (){
        var $thiz = $(this);
        var val = $thiz.val();
        var placeholder;
        return function (){
            
            if(val === ''){
                $thiz.val(placeholder);
                placeholder = null;
            }else{
                if(!placeholder){
                    placeholder = $thiz.val();
                    $thiz.val('');
                }else{
                    placeholder = null;
                }
            }
        };
    };

    
    $('.login_popup input').on('focus', dominos.clearPlaceholder).on('blur', dominos.clearPlaceholder);

Автор: Сергей Бабинский (не зарегистрирован), дата: 1 ноября, 2012 - 11:33
#permalink

Ваша функция возвращает функцию, но возвращенная так и не вызывается. Попробуйте так:

$('.login_popup input').on('focus', dominos.clearPlaceholder()).on('blur', dominos.clearPlaceholder());

Автор: Studentka (не зарегистрирован), дата: 11 августа, 2012 - 08:44
#permalink

Правильно ли я поняла, что для, например, для div 1 получается
onclick = function(x) {alert(x)} при этом в области видимости хранится x:1
для div2
onclick = function(x) {alert(x)} при этом в области видимости хранится x:2
Получается мы передаем в onclick функцию с ее областью видимости.
а если без замыканий, тогда получается, что onclick для div 1 будет

onclick = function {alert(i)} и он возьмет i из внешней функции и для div2 будет аналогично.

Помогите новичку. Я вроде поняла, но чувствую, что еще плаваю.


Автор: Ang15 (не зарегистрирован), дата: 27 января, 2013 - 15:27
#permalink

Функция addHideHandler приводит к желаемому результату (сокрытию стороннего элемента) только, когда нажмешь на первый элемент два раза. Может, для функции addHideHandler следует ввести оператор return? Или это для того, чтобы люди лишний раз подумали? ))


Автор: Гость (не зарегистрирован), дата: 1 февраля, 2013 - 19:36
#permalink

"Интерпретатор javascript не проводит анализ - понадобятся ли внутренней функции переменные из внешней, и какие переменные могут быть нужны.
Вместо этого он просто оставляет весь [[scope]] внешней функции в живых.
Чтобы когда внутренняя функция запустится, если она вдруг не найдет какую-либо переменную в своем [[scope]] - она могла обратиться к [[scope]] внешней функции и нашла бы ее там."

Это неверно. Скоуп внешней функции не уничтожается из-за особенностей работы сборщика мусора. Пока на какой-либо объект существует хоть одна ссылка из другого контекста (в данном случае ссылка на [[scope]] внешней функции из внутренней функции) этот объект не может быть уничтожен сборщиком мусора. Причина в этом а не в том что внутренней функции МОЖЕТ понадобиться переменная из внешней функции


Автор: Гость (не зарегистрирован), дата: 15 марта, 2013 - 22:44
#permalink

Помогите зациклить

<SCRIPT LANGUAGE="javascript">
function test() {
alert('11111');
document.getElementById('test').onclick=function () {
alert('22222');
}};
</SCRIPT>

<strong id='test' onclick="test();">Click here</strong>


Автор: Гость (не зарегистрирован), дата: 17 марта, 2013 - 17:47
#permalink

Спасибо. Удружили доступно изложенной информацией.


Автор: Монгол (не зарегистрирован), дата: 23 апреля, 2013 - 22:07
#permalink

Замыкание - одно из мощных выразительных средств javascript, которым часто пренебрегают, и даже не советуют употреблять.

Действительно, замыкания могут приводить к проблемам.

эти слова я думаю стоит выделить красным жирным написанием размером в 200 пикселей на букву


Автор: Max_Cohen (не зарегистрирован), дата: 4 мая, 2013 - 13:49
#permalink

Привет!
Почему Я не могу получить значение return в переменную aname?
Выводит undefined.

function at1cx(id){
	var aname=aajax(id);
}
function aajax(id){
	var a=new XMLHttpRequest();
	var b=false;
	a.open("GET","a.php?a="+id.value,true);
	a.onreadystatechange=function(){
		if(a.readyState==4)
			if(a.status==200){
				aspan.innerHTML=a.responseText;
				if(a.responseText>0)
					return 'F';
				else
					return 'T';
			}
	}
	a.send(null);
}

А как получить значение return?


Автор: koeshiro, дата: 22 октября, 2013 - 11:17
#permalink

Одна из переменных может не перидоваться сервером. Нужно проверит php script. Может отсутствовать a.responseText; Или являться пустой строкой. А может и не быть aspan Но его вообще негде не видно.


Автор: Гость (не зарегистрирован), дата: 28 марта, 2014 - 19:22
#permalink

так как вызывается функция aajax , а не onreadystatechange , то соответственно функция aajax возвращяет undefined.

что-бы переменная приняла значение можно воспользоваться callback функцией:

function at1cx(id) {
var aname;
aajax(id, function (res) {
aname = res;
});
}
function aajax(id, callback) {
var a = new XMLHttpRequest();
var b = false;
a.open("GET", "a.php?a=" + id.value, true);
a.onreadystatechange = function () {
if (a.readyState == 4)
if (a.status == 200) {
aspan.innerHTML = a.responseText;
if (a.responseText > 0)
callback('F');
else
callback('T');
}
}
a.send(null);
}


Автор: koeshiro, дата: 22 октября, 2013 - 11:13
#permalink

Спасибо очень помоги =)
Теперь можно делать кросс браузерные табы.


Автор: Naza (не зарегистрирован), дата: 7 ноября, 2013 - 20:12
#permalink

Вот еще простой пример замыкания:


var object = {
index: 0,
add: function() {
this.index++;
return this; //дает возможность вызывать функции цепочкой
},
get: function() {
return this.index;
}
};

object.add().add().add().get(); // >> 3


Автор: Гость (не зарегистрирован), дата: 27 ноября, 2013 - 03:49
#permalink

Большое спасибо.
Очень понятно все написано.
Полдня убил пытаясь проблему решить.


Автор: dtsiv (не зарегистрирован), дата: 14 января, 2014 - 22:30
#permalink

Спасибо за отличный учебник!

Заметил, что ссылка выше переехала сюда или около того (страничку можно достать из кэша Гугл).


Автор: Гость (не зарегистрирован), дата: 16 июня, 2014 - 09:43
#permalink

Автор - это редкий случай, когда у программиста получается писать статьи не только для таких же программистов, но и для обычных людей.
Спасибо, Илья, за вашу работу.


Автор: Qzz (не зарегистрирован), дата: 23 ноября, 2014 - 05:29
#permalink

Здравствуйте. Подскажите пожалуйста, как можно написать код в данной ситуации:

У меня n количество маленьких картинок и 1 большая. При нажатии на любую из маленьких картинок, нужно большую убирать, а вместо нее ставить маленькую с уникальным id (в качестве идентификатора, можно использовать название маленькой картинки, 101.jpeg). Этот id нужно присвоить глобальной переменной.

<script>
Вот тут не понятно, что написать, чтобы шла смена картинок с присвоением id маленькой картинки?
</script>
// массив картинок
$img = '101.jpeg, 102.jpeg, ... , n';

// большая картинка
echo '<img id="cImg" src="/100.jpeg">';

for ($i=0; $i<$n; $i++) {
// маленькие картинки
echo '<img src="/'.$img[$i].'" onclick="nextImage($img)"> ';
}

Буду благодарен любым советам.


Автор: Гость (не зарегистрирован), дата: 17 января, 2015 - 23:02
#permalink

   

)))


Автор: SeregaRiga (не зарегистрирован), дата: 28 января, 2015 - 16:23
#permalink

нагляднее для изучающих было бы выложить весь код "верных" и "неверных" функций, чтоб они у себя в Notepad++ погоняли код, вот, выкладываю этот пример с html- разметкой и кодом JS:

<!doctype html>
<html lang="ru">
<head>
<title>Спящий onclick при вызове внутренней функции вызывает для внутренней функции внешний LE момента ОКОНЧАНИЯ выполнения внешней функции</title>
<meta charset="utf-8">
</head>
<body>

<p>
<input type="button" onclick="testEvents()" value="запускаем функцию testEvents()">
</p>
<p><input type="button" onclick="testEvents2()" value="запускаем функцию testEvents2()"></p>

<div id="events1"></div>
 <div id="events2"></div>

</div>
[js]
<script>

function makeDivs(parentId) {
	for (var i=0;i<10;i++) {
		var j = 9-i; //j будет 9, 8, 7, 6 ...0
		var div = document.createElement('div');
		div.style.backgroundColor = '#'+i+i+j+j+j+i
		div.className="closure-div"
		div.style.color = '#'+j+j+i+i+i+j
		document.getElementById(parentId).appendChild(div)
		//все верно: она тут строит рядок из div, варьируя цвета
	}
}

function testEvents() {
	makeDivs('events1')// отдаем стринг-значение id <div id="events1"></div>
	addEvents(document.getElementById('events1').childNodes)
	//.childNodes берет массив дочерних элементов, функция makeDivs(parentId)) запиздячила туда рядок из них (разных цветов)
}


function addEvents(divs) { // вот якобы ошибочная функция

	for(var i=0; i<divs.length; i++) {	//получила массив дочерних div, будет расставлять на них циферки, выводимые при .onclick 
		divs[i].innerHTML = i
		divs[i].onclick = function() { alert(i) } // вот эта i в alertе почему-то будет 10, в этом и закавыка, вроде как по логике должны быть от 0 до 10. Тут соль задачи.Учебник говорит: "Такой глюк возник из-за того, что все функции div[i].onclick получают значение i из одного на всех [[scope]] внешней функции. А это значение ([[scope]].i) НА МОМЕНТ АКТИВАЦИИ ONCLICK-ОБРАБОТЧИКА РАВНО 10 (цикл завершился как только i==10)". ТО ЕСТЬ внутренняя функция хватает значение i именно НА МОМЕНТ АКТИВАЦИИ ONCLICK-ОБРАБОТЧИКА, а это 10. То есть внутреннее поле переменных как бы в ином временном измерении, оно хватает из внешнего lexical evironment именно на момент активации .onclick значение i. При .onclick имеется как бы спящая  внутренняя функция, которая при активации просыпается и хватает самое последенее значение из внешнего lexical evironment, а оно тут 10. Это скорее особенность обработчика событий .onclick
	}
	
	
}


function testEvents2() {
	makeDivs('events2')
	addEvents2(document.getElementById('events2').childNodes)
		//.childNodes берет массив дочерних элементов, тут он пока пустой)
}

function addEvents2(divs) {
	for(var i=0; i<divs.length; i++) {	
		divs[i].innerHTML = i
		divs[i].onclick = function(x) {
			return function() { alert(x) }
		}(i) // а вот тут мы запихиваем именно из внешней функции значение i КАЖДОГО ОБОРОТА
	}
}


</script>[/js]
</body>
</html>

Автор: Антананариву (не зарегистрирован), дата: 8 января, 2016 - 15:25
#permalink

function makeShout() { // (1)
var phrase = "Превед!" // (2)

var shout = function() { // (3,4)
alert(phrase)
}

phrase = "Готово!" // (5)

return shout
}

shout = makeShout()
// что выдаст?
shout()

объясните, пожалуйста, зачем в этом примере мы приравниваем функцию shout к makeShout? Не могу разобраться.


Автор: Василий228 (не зарегистрирован), дата: 8 января, 2016 - 17:23
#permalink

121331212


Автор: Гость (не зарегистрирован), дата: 10 марта, 2016 - 03:07
#permalink

так как всё таки работает Сборщик мусора?
сам алгоритм получение разрешения на удаление Объекта активации ?


Автор: Гость (не зарегистрирован), дата: 10 марта, 2016 - 03:11
#permalink

(поспешил отправить)
мне кажется многое станет ясно и прозрачно, если будет чёткое понимание алгоритма процесса "уборки мусора".
хотя в разных браузерах это может реализовано по разному.
в Спецификации то же ничего нет.


Автор: dkhorosh (не зарегистрирован), дата: 27 мая, 2016 - 13:41
#permalink

Мне понравилось объяснение замыканий в этом видео в самом конце (1 час 49 минута) https://youtu.be/Wdg0p4QGV6s?t=1h49m30s


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

Приветствуются комментарии:
  • Полезные.
  • Дополняющие прочитанное.
  • Вопросы по прочитанному. Именно по прочитанному, чтобы ответ на него помог другим разобраться в предмете статьи. Другие вопросы могут быть удалены.
    Для остальных вопросов и обсуждений есть форум.
P.S. Лучшее "спасибо" - не комментарий, как все здорово, а рекомендация или ссылка на статью.
Содержание этого поля является приватным и не предназначено к показу.
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Разрешены HTML-таги: <strike> <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <u> <i> <b> <pre> <img> <abbr> <blockquote> <h1> <h2> <h3> <h4> <h5> <p> <div> <span> <sub> <sup>
  • Строки и параграфы переносятся автоматически.
  • Текстовые смайлы будут заменены на графические.

Подробнее о форматировании

CAPTCHA
Антиспам
7 + 5 =
Введите результат. Например, для 1+3, введите 4.
 
Текущий раздел
Поиск по сайту
Реклама
Содержание

Учебник javascript

Основные элементы языка

Сундучок с инструментами

Интерфейсы

Все об AJAX

Оптимизация

Разное

Дерево всех статей

Последние комментарии
Последние темы на форуме
Forum