将静态值传递给动态Javascript函数

时间:2011-09-14 02:27:45

标签: javascript javascript-events google-maps-api-3

所以我确信这是一个简单的问题但是无法解决这个问题。下面显示了在'mousedown'事件中创建并添加到谷歌地图标记的功能。这是为迭代的每个标记创建的。

包含我的部分位于'pickupVenue(data [i] .id)'下面的第5行,此函数调用中提交的值始终是最后一个迭代值。我想在创建每个标记时坚持我正在迭代的静态值。

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeout(function() { pickupVenue(data[i].id) }, 1000); 
    });
}

----工作结果----

google.maps.event.addListener(marker, 'mousedown', pickupMarker(data[i].Listing.id));

function pickupMarker(id) {
    return function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeout('pickupVenue('+id+')', 1000);
    }
}

3 个答案:

答案 0 :(得分:2)

您需要确保您传递的函数作为事件侦听器在其作用域中有一个变量,该变量引用i在循环中保留的值而不进行修改i被修改。

目前,您在循环中创建的所有函数都共享相同的i变量,因此在最终调用处理程序时,它们最终都会获得任何值i引用。

在JavaScript中,创建新变量作用域的唯一方法是调用一个函数,并在该函数中创建一个引用所需值的局部变量(或参数)。

像这样:

function createListener( i ) {
    return function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeout(function() { pickupVenue(data[i].id) }, 1000); 
    };
}

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', createListener( i ) );
}

在这里,我创建了一个createListener()函数,并将i传递给它。

因为现在正在createListener()函数内创建侦听器函数,所以该侦听器将引用该变量作用域中的i,这将继续保留调用{{1}时给出的任何值。 1}}(除非你的函数修改createListener())。

然后i 返回该侦听器函数,该函数作为第三个参数传递给createListener()

答案 1 :(得分:1)

来自IAbstractDownvoteFactor的Closure答案的增强版:

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', function() {
        state = PINCH;
        map.setOptions({draggable: false});

        var timeoutFn = function(theId) {
            return function realTimeoutFn() {
                pickupVenue(theId); // value of "theId" is kept
            };
        };

        timeoutId = setTimeout(timeoutFn(data[i].id), 1000); 
    });
}

答案 2 :(得分:0)

我看到setTimeout()这个问题频繁出现,记住正确的闭包语法总是很麻烦,所以我想也许我们应该创建一个setTimeoutWithData()实用函数,这样可以很容易。所以这就是:

function setTimeoutWithData(rock, fn, t, ctx) {
    ctx = ctx || window;
    function localFn() {
        fn.call(ctx, rock);
    }
    return(setTimeout(localFn, t));
}

它需要四个参数并返回timerID:

rock

这是任何类型的数据都将传递给您的回调。如果你想传递大量数据,你可以将rock变成一个对象或一个数组。

fn

这是你的回调函数。它将作为参数传递给rock,因此你的回调应该像这样声明:function fn(rock) {}

t

这是以ms为单位的setTimeout时间值,与setTimeout相同。

ctx

这是唯一的可选参数。如果您希望回调具有特定的this值,则可以使用ctx参数进行配置。除此之外,这允许您使用setTimeoutWithData来调用对象上的方法并适当地设置this,以便使用面向对象的编程更容易地工作。如果未传递ctx,则this将设置为window(与setTimeout相同)。

所以,原问题中的问题可以这样解决:

for (i in data) {
    google.maps.event.addListener(marker, 'mousedown', function() {
        state = PINCH;
        map.setOptions({draggable: false});
        timeoutId = setTimeoutWithData(data[i].id, function(anID) { pickupVenue(anID) }, 1000); 
    });
}

并且,这是一个示例应用程序,显示此实用程序功能的运行:http://jsfiddle.net/jfriend00/3SUAJ/