javascript - Javascript 中的闭包遇到问题

标签 javascript google-maps-api-3 closures

我试图将一个数组传递到一个函数中,然后使用该数组中的信息来初始化谷歌地图。但是,当我单击 map 上的标记时,会产生错误:

Unable to get value of the property 'popupHtml': object is null or undefined

创建该函数的原因是为了将 JavaScript 代码移动到单独的 .js 文件中,从而与 html 文件分开。这个问题有办法解决吗?这是我的所有代码(我添加了注释来标记发生错误的位置...):

<!DOCTYPE html>

<html>
<head>    
    <script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?sensor=false"></script>
    <script type="text/javascript">
        window.onload = function ()
        {
            function loadMap(markers)
            {
                var options =
                {
                    center: new google.maps.LatLng(40.775813, -73.970786),
                    zoom: 17,
                    mapTypeId: google.maps.MapTypeId.ROADMAP
                };
                var map = new google.maps.Map(document.getElementById('map'), options);

                var points = new Array();
                for (var i = 0; i < markers.length; i++)
                    points.push(new google.maps.LatLng(markers[i].lat, markers[i].lon));
                var infoWindow = new google.maps.InfoWindow();
                for (var i = 0; i < markers.length; i++)
                {
                    var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: markers[i].title });
                    google.maps.event.addListener(
                        googleMarker,
                        'click',
                        function ()
                        {
                            // The following line is where the error is occuring:
                            infoWindow.setContent(markers[i].popupHtml);
                            infoWindow.open(map, googleMarker);
                        });
                }
            };

            loadMap([{
                "lat": "40.776512",
                "lon": "-73.970293",
                "popupHtml": "\u003cdiv\u003eHello world - from marker 1!\u003c/div\u003e",
                "title": "Marker 1!"
            },
            {
                "lat": "40.774659",
                "lon": "-73.971548",
                "popupHtml": "\u003cdiv\u003eHello world - from marker 2!\u003c/div\u003e",
                "title": "Marker 2!"
            }]);
        };
    </script>
</head>
<body>
    <div id="map" style="width: 680px; height: 400px;"></div>
</body>
</html>

最佳答案

问题在于您传递给 addListener 的函数具有对 i 变量的持久访问权限,而不是其值的副本自该函数创建时起。因此,该函数的所有副本在调用时都会看到 i,这可能超出了数组的末尾。 googleMarker 也是如此;他们都会看到循环中的最后值,而不是当前值。

您可以通过使用生成器函数来修复它,或者(如果您可以依赖 ECMAScript5,或者如果您使用 ES5 填充程序,因为 bind 是填充程序可以提供的东西)使用 Function#bind .

使用绑定(bind):

for (var i = 0; i < markers.length; i++)
{
    var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: markers[i].title });
    google.maps.event.addListener(
        googleMarker,
        'click',
        (function (index, thisMarker)
        {
            // The following line is where the error is occuring:
            infoWindow.setContent(markers[index].popupHtml);
            infoWindow.open(map, thisMarker);
        }).bind(undefined, i, googleMarker)
    );
}

bind 返回一个函数,在调用该函数时,将使用给定的 this 值和您提供的参数来调用原始函数。因此,在上面,我们调用 bind 并传入 igoogleMarker,它给了我们一个函数在被调用时将使用这些值作为参数来调用我们的原始函数。然后我们使用参数(indexthisMarker)而不是 igoogleMarker

如果您不能依赖目标浏览器中的 ES5 功能并且不想使用填充程序,则可以使用生成器函数:

for (var i = 0; i < markers.length; i++)
{
    var googleMarker = new google.maps.Marker({ position: points[i], map: map, title: markers[i].title });
    google.maps.event.addListener(
        googleMarker,
        'click',
        makeHandler(i, googleMarker)
    );
}

function makeHandler(index, thisMarker) {
    return function ()
    {
        // The following line is where the error is occuring:
        infoWindow.setContent(markers[index].popupHtml);
        infoWindow.open(map, thisMarker);
    };
}

我们调用 makeHandler,传入 igoogleMarker,以及 makeHandler 返回一个函数,该函数关闭这些参数(indexthisMarker),而不是 igoogleMarker。由于 makeHandler 参数不会更改,因此我们的函数将看到正确的值。

这一切都与闭包的工作方式有关。有关关闭的更多信息:Closures are not complicated

关于javascript - Javascript 中的闭包遇到问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10395524/

相关文章:

javascript - jQuery Mobile 与 Sencha Touch

javascript - jsp Ajax 不工作

javascript - 使用 ajax 进行 Bootstrap 模式更新

java - 如何在谷歌地图静态 API 中的标记上显示标签(字符串)?

objective-c - 以 Swift 方式将 Objective-C block 转换为闭包

javascript - 选择选项后重定向不起作用

google-maps-api-3 - 使用 Google map 标记图标附加 HTML

javascript - google maps api v3 - javascript - 透视/倾斜(不是卫星!)?

ios - 从 Swift 中的闭包返回多个 View 对象

PHP5 : Callbacks between Class Objects