var found={};
database.iterate_records(
function(record){ found[record.phone]=record.name; }
);
Напишем простой тест. Определим десять функций, печатающих числа от 0 до 9 и вызовем их последовательно:
var a=[];
for(var i=0; i<10; i++) a.push(function(){ document.write(i); });
for(var i=0; i<10; i++) a[i]();
Запускаем, получаем: "0123456789". Что и требовалось, так? Ship it!Теперь изменим немножко заменив переменную во втором цикле:
var a=[];
for(var i=0; i<10; i++) a.push(function(){ document.write(i); });
for(var j=0; j<10; j++) a[j]();
Что ожидаем? То же самое. Что получаем? "10101010101010101010". Как это?Это очень просто. Замыкание захватывает не значение i в какой-то момент времени, а саму переменную, объект переменной. Выражение document.write(i) печатает текущее значение переменной i сейчас, а те то, которое было в момент, когда создавалась 'function'. Это очень важная особенность javascript, которая часто приводит к большому количеству ошибок.
Ok, скажем мы, давайте изменим, чтобы была не переменная, а выражение:
var a=[];
for(var i=0; i<10; i++) a.push(function(){ document.write(i+' '); });
for(var j=0; j<10; j++) a[j]();
Получаем: "10 10 10 10 10 10 10 10 10 10 ". Не помогает.Потому, что выражение вычисляется в момент вызова функции, а не в момент создания замыкания.
Сделаем копию:
var a=[];
for(var i=0; i<10; i++){ var ii=i; a.push(function(){ document.write(ii); }); }
for(var j=0; j<10; j++) a[j]();
Получаем "9999999999". Как это?Потому, что замыкание захватило переменную ii. И текущее значение ii = последнее, что было присвоено = 9.
Ну и что можно сделать? Единственное, что можно сделать в javascript, это вызвать функцию с параметром. Параметры передаются по копии значения, а не по ссылке. Как-то так:
var a=[];
for(var i=0; i<10; i++) a.push(
function(i){ return function(){ document.write(i); }} (i)
);
for(var j=0; j<10; j++) a[j]();
Получаем "0123456789". Ура! Заработало. Теперь не забыть писать такое везде, где есть замыкание. Здорово, правда?Понятно почему так? Здесь i в замыкании и i цикла - разные i. Можно заменить внутреннюю i:
var a=[];
for(var i=0; i<10; i++) a.push(
function(a){ return function(){ document.write(a); }} (i)
);
for(var j=0; j<10; j++) a[j]();
Здесь мы определяем функцию и тут же ее вызываем: function(a){...}(i)Этот вызов создает копию значения переменной i и присваивает его параметру a.
Результатом этой функции будет уже замыкание, которое захватило a, и это a - локальная переменная функции, поэтому каждый вызов порождает новый экземпляр a и каждое замыкание захватывает свою переменную, а не все одну и ту же, как в первых примерах.
Такая вот захватывающая история. Как с этим практически работать без превращения кода в нечитаемый кошмар напишу в одном из следующих выпусков. А пока попробую подсветить синтаксис в приведенных примерах. Заранее извиняюсь за многочисленные обновления данного текста.
3 comments:
Немного не в тему, но ты меня прости. (полезная вещица.)
Если в HTML добавить строку:
script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=default"
(скобочки не забудь добавить)
То модно станет писать формулы в формате ЛатеХа. Проверь сам (тестовая строка):
\(G(x,y)=\sum\limits_{i=0}^{\infty}X_i(x)Y_i(y)\)
Ты можешь сам заказывать размер и цвет шрифта формулы.
Да, mathjax я видел. Если бы писал формулы, наверняка бы воспользовался. А до этого была mimetex, на стороне сервера. У меня даже на сайте стоит: test
mimetex генерит битмап, а MathJax динамически (внутри браузера) из ЛаТеха генерит HTML.
Я свою монографию опубликовал в Internet.
http://bolshoyforum.com/forum/index.php?topic=410865.0
Post a Comment