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