Javascript Closures и переменная область действия - PullRequest
2 голосов
/ 10 августа 2011

Я расширяю свой предыдущий вопрос , потому что я до сих пор не до конца понимаю концепцию закрытия javascript.Взгляните на следующий код, который поместит два маркера на карту.(Код немного изменен по сравнению с моим предыдущим вопросом).

var map = google.maps.somefunctoinstantiatemap();
var address = new Array();
address[0] = '1 Smith Street';
address[1] = '2 Smith Street';
function onpageload()
{
for(var rownum=0; rownum<address.length; rownum++)
{
    geocoder.geocode({
        'address': address[rownum]
    }, function(results, status) {
        geocodeCallBack(results,status,rownum)
    });
}
}

function geocodeCallBack(results, status, argnum)
{
    var marker = new google.maps.Marker({
        map: map,
        position: results[0].geometry.location,
        title: 'arg: '+argnum+' addr:'+results[0].formatted_address
    });

    google.maps.event.addListener(marker, 'click', function(){
        var infowindow = new google.maps.InfoWindow({
            content: marker.title
        });
        infowindow.open(map, marker);
    });
}

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

  1. первый маркер отображает 'arg: 0 addr: 1 Smith Street'и второй маркер отображает «arg: 1 адрес: 2 Smith Street»
  2. первый маркер отображает «arg: 0 адрес: 2 Smith Street» и второй маркер отображает «arg: 1 addr: 2 Smith Street»
  3. первый маркер отображает «arg: 1 адрес: 1 Smith Street», а второй маркер отображает «arg: 1 addr: 2 Smith Street» *
  4. первый маркер отображает «arg: 1 addr: 2 Smith Street» ивторой маркер отображает 'arg: 1 адрес: 2 Smith Street'
  5. первый маркер отображает 'arg: неопределенный адрес: undefined' и второй маркер отображает 'arg: неопределенный адрес: undefined'

Когда я запускаю код, ответ равен 3. Но я ожидал, что ответ будет 4 или 5. Почему это не 4 и почему это не 5?

Ответы [ 2 ]

4 голосов
/ 10 августа 2011

Вы, похоже, ожидаете, что замыкание закроется над чем-то (что оно делает), но вы не используете ничего, в частности, что оно замыкается в нем (например, индекс цикла). Значение argnum, которое вы получаете в своем geocodeCallBack, исходит от Google (поскольку вы определили rownum в качестве третьего аргумента для вашей анонимной функции, shadowing счетчик цикла), это не имеет ничего общего с Ваш счетчик циклов.

Несколько других замечаний по поводу этого кода:

Ваш цикл вверху цикличен три раза, а не два. У вас это происходит от 0 до <= results.length. results.length - это 2, поэтому цикл будет иметь значения rownum 0, 1 и 2. Вы имеете в виду < results.length. (Вы это исправили.)

Ваша анонимная функция здесь не нужна:

geocoder.geocode( {'address': address[rownum]}, function(results, status, rownum) {geocodeCallBack(results,status,rownum)});

... поскольку все, что он делает, это передает аргументы, которые он получает. Это может и, вероятно, должно быть просто:

geocoder.geocode( {'address': address[rownum]}, geocodeCallBack);

... если только подпись функции неверна и вам не следует объявлять все эти аргументы ей.

Редактировать : Исходя из ваших комментариев ниже, я думаю, вы можете захотеть это:

geocoder.geocode( {'address': address[rownum]}, makeCallback(rownum));

function makeCallback(therow) {
    return function(results, status) {
        geocodeCallBack(results, status, therow);
    };
}

... или в вашем «реальном коде», как вы его назвали, где вы фактически используете этот номер строки как часть селектора:

geocoder.geocode( {'address': address[rownum]}, makeCallback(rownum));

function makeCallback(therow) {
    return function(results, status) {
        geocodeCallBack(results, status, $('#row-' + therow).val());
    };
}

Функция makeCallback создает функцию для обратного вызова. Создаваемая функция закрывает аргумент therow, переданный в makeCallback, который никогда не меняется, и вы получаете therow, являющийся 0 для обратного вызова, созданного в первом цикле, и therow, являющийся 1 для обратного вызова, который вы создаете во втором цикле.

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

0 голосов
/ 10 августа 2011

geocode () переопределяет значение numrow, когда вы объявляете его как параметр функции.

for(var rownum=0; rownum<=address.length; rownum++)
{
        geocoder.geocode( {'address': address[rownum]}, function(results, status) {geocodeCallBack(results,status,rownum)});
}

Попробуйте вместо этого, таким образом, geocodeCallBack отправляет значение rownum, объявленное в forloop

Результатом должно быть отображение первого маркера 'arg: 0 addr: 1 Smith Street' и отображение второго маркера 'arg: 1 addr: 2 Smith Street'

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