为什么我在这个for循环之后只得到最后一个id道具?

时间:2012-02-08 00:52:40

标签: javascript jquery for-loop

我可能错误地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'}})

我不确定我在这里缺少什么,我怎么能避免这个?

我怀疑问题可能出在setImageSize方法中,该方法加载了img元素background image,需要保存真正的widthheight。< / p>

是否会出现负载延迟?

我不确定因为测试会在for循环中讨论错误的道具分配。

这里是http://jsfiddle.net/tonino/CFPTa/我确定问题出在jquery load事件中,但我不确定如何解决它。

2 个答案:

答案 0 :(得分:3)

你所写的内容的问题源于封闭效应。

在您的匿名悬停函数中,您指的是i变量,但在所有迭代完成之前,不会调用该事件。当您在匿名函数中引用i变量时,它不会像当时那样获取i的副本 - 它只是使用对它的引用。这意味着当你递增i变量时,你也会增加匿名函数引用的变量,所以在所有三次迭代之后,你所做的所有三个匿名函数都引用相同的{{1} }值:2。

我相信制作方法工厂方法会起作用,如下所示:

i

调用工厂方法时,返回的函数将在调用时捕获工厂函数的范围 - 这意味着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()); }); } 变量现在不会更改。

有关详情,请参阅此帖子:http://msdn.microsoft.com/en-us/scriptjunkie/ff696765

答案 1 :(得分:0)

这与关闭有关。在循环完成之前,函数不会运行。您可以使用立即调用的函数来解决此问题。

// 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/