Почему я получаю только последние реквизиты после цикла for? - PullRequest
1 голос
/ 08 февраля 2012

Я, вероятно, ошибаюсь, как JavaSript назначает свойства в for loop, как я могу исправить эту проблему?

var setImageSize = function (i) {

    instances[i].img = $('<img id="jquery-background-zoom-'+i+'"/>');
    var img = instances[i].img;
    img.hide();
    img.bind('load', function(e) {
        var id = parseInt($(this).attr('id').replace('jquery-background-zoom-', ''));
        instances[id].settings.bg.width = parseInt($(this).width());
        instances[id].settings.bg.height = parseInt($(this).height());

        $('#debug').html($('#debug').html() + '[' + i + ' ' + instances[id].settings.bg.width + ', ' + instances[id].settings.bg.height + ']<br>');
        updateDefaultValues(instances[id]);

        $(this).remove();
    });
    $('body').append(img);
    img.attr('src', instances[i].settings.bg.url);
}

var setEvent = function (i) {
    return function (e) {
        var inst = instances[$(this).index()];
        $('#debug').html(i + ' ' + inst.settings.bg.url);
        $(this).bind('mousemove', {i:instances[$(this).index()]}, setFollowMouse);
    }
}

var init = function (options) {

    for (var i = 0; i < this_obj.length; i ++) {

        instances.push ({id:i, element:this_obj.get(i), settings:$.extend(true, defaults, options)});
        instances[i].settings.bg.url = $(this_obj.get(i)).css('background-image').replace('url(', '').replace(')', '').replace(/'/g, '').replace(/"/g, '');

        $('#debug').html($('#debug').html() + '<br>' + i + ' -- ' + instances[i].toSource() + '<br><br>');

        setImageSize (i);

        $(instances[i].element).hover(setEvent(i), function () {
            $(this).unbind('mousemove', setFollowMouse);
            zoomOut($(this).index());
        });
    }
}

init(); // at the bottom of jQuery plug-in

в first test Я получаю то, что ожидаю:

({id:0, settings:{url:"http://localhost/js/img/example_0.jpg", other_propos:'relative to the id 0'}})
({id:1, settings:{url:"http://localhost/js/img/example_1.jpg", other_propos:'relative to the id 1'}})
({id:2, settings:{url:"http://localhost/js/img/example_2.jpg", other_propos:'relative to the id 2'}})

в event test, когда я вызываю событие mousemove, я получаю только last element propos, но право id, почему?

({id:0, settings:{url:"http://localhost/js/img/example_2.jpg", other_propos:'relative to the id 2'}})
({id:1, settings:{url:"http://localhost/js/img/example_2.jpg", other_propos:'relative to the id 2'}})
({id:2, settings:{url:"http://localhost/js/img/example_2.jpg", other_propos:'relative to the id 2'}})

I 'я не уверен, что мне здесь не хватает, как я могу избежать этого?

Я подозреваю, что проблема может быть в методе setImageSize, который загружает элемент img background image, необходимый для сохранения его реального состояния.width и height.

Может ли это быть в задержке загрузки?

Я не уверен, потому что тесты говорят о неправильном назначении реквизита в цикле for.

здесь http://jsfiddle.net/tonino/CFPTa/ Я уверен, что проблема в событии загрузки jquery, но я не уверен, как ее решить.

Ответы [ 2 ]

3 голосов
/ 08 февраля 2012

Проблема с тем, что вы написали, проистекает из эффекта закрытия.

Внутри вашей анонимной функции наведения вы ссылаетесь на переменную i, но это событие не вызывается, пока не пройдут все итерации. Когда вы ссылаетесь на i variabe внутри анонимной функции, она не берет копию i, как это было в то время - она ​​просто использует ссылку на нее. Это означает, что когда вы увеличиваете переменную i, вы также увеличиваете ту, к которой относится анонимная функция, поэтому после всех трех итераций все три сделанные вами анонимные функции ссылаются на одно и то же значение i: 2 .

Я считаю, что создание метода фабрики методов будет работать следующим образом:

var factory = function(i) {
    return function (e) {

        var inst = instances[$(this).index()];
        // event test, here I get only the last instance propos but the right id, why??
        $('#debug').html($('#debug').html() + '<br>' + inst.toSource() + '<br>');

        $(this).bind('mousemove', {i:instances[$(this).index()]}, setFollowMouse); // e.data.id
    }
}
for (var i = 0; i < this_obj.length; i ++) {
    instances.push ({id:i, element:this_obj.get(i), settings:$.extend(true, defaults, options)});
    instances[i].settings.bg.url = $(this_obj.get(i)).css('background-image').replace('url(', '').replace(')', '').replace(/'/g, '').replace(/"/g, '');

    // first test
    $('#debug').html($('#debug').html() + '<br>' + instances.toSource() + '<br>');

    $(instances[i].element).hover(factory(i), function () {
        $(this).unbind('mousemove', setFollowMouse);
        zoomOut($(this).index());
    });
}

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

См. Этот пост для более подробной информации: http://msdn.microsoft.com/en-us/scriptjunkie/ff696765

0 голосов
/ 08 февраля 2012

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

// will awlays output 5

    for (var i = 0, len = 5; i < len; i += 1) {
        setTimeout(function () {
          console.log(i);
        }, 100);   
    }

    // this is correct
    for (i = 0, len = 5; i < len; i += 1) {
        (function (i) { // notice the immediately invoked function
            setTimeout(function () {
              console.log(i);
            }, 100);   
        }(i));
    }

http://jsfiddle.net/LBahU/

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