Основы программирования на JavaScript | страница 47



this.sleep = function(){ alert(name+' спит: Хрррр'); }

}


Можно не заметить этого, но переменная 'name' в функции sleep приходит из родительской функции Animal. Это создает замыкание.

Даже определение простейшей функции может создавать замыкание:


var x = 5;

var n = function(){

y=10;

return y;

}


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

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


var x = 5;

var alertX1 = function(){ alert(x); }

x = 10;

var alertX2 = function(){ alert(x); }

alertX1();

alertX2();


Обе функции в этом случае выведут 10. Почему? Потому что они обе указывают на одну и ту же копию х.



Если изменить x в любой точке, то обе функции отразят это. Как это исправить? Проще всего изменить область действия замыкания:


function makeClosure(x){

return function(){ alert(x); }

}

var x = 5;

var alertX1 = makeClosure(x);

x = 10;

var alertX2 = makeClosure(x);

alertX1(); // 5

alertX2(); // 10


Это решает проблему. Если, однако, этот код создавал утечку памяти, то утечка будет существенно больше, чем в предыдущем примере; и также используется больший объем памяти. Оказывается, что в действительности имеется три различных области действия в этом простом примере:



Можно видеть, что переменная х копируется в каждую из двух областей действия. Это связано с тем, что x является строкой или числом. JavaScript всегда передает строки и числа по значению - то есть всегда делается копия переменной. С объектами все происходит иначе. Если х является функцией, массивом или базовым объектом, то в этом случае ссылка в двух наших функциях происходит на одну и ту же копию x и поэтому в результате выводимое сообщение будет одинаковым:


function makeClosure(x){

return function(){ alert(x.val); }

}

var x = {val:5};

var alertX1 = makeClosure(x);

x.val = 10;

var alertX2 = makeClosure(x);