变量在函数外变得未定义

Variables becomes undefined outside of function

所以我一直在使用 leaflet.js 创建我家乡的疫苗接种点地图,并尝试使用路由找到离用户最近的站点,但是当我记录或尝试在函数外调用它。我对 js 比较陌生,在 python 中使用 folium 时了解了 leaflet。在 python 中,我认为您只需声明您正在更改全局变量或更好地使用 return,但我不确定如何使用 js 和传单库来做到这一点。

var self_lat;
var self_long;
...
var mymap = L.map('mapid').setView([34.7465, -92.2896], 6);
...
function onLocationFound(e) {
    console.log(e);
    self_lat =  e.latitude;
    self_long = e.longitude;
    L.marker([e.latitude, e.longitude], {icon: home_marker}).bindPopup("YOU ARE HERE!").addTo(mymap);
    console.log(typeof(e.latitude))
    console.log(typeof(e.longitude))
}

function onLocationError(e) {
    alert(e.message);
}
mymap.locate({setView: false, maxZoom: 16});
mymap.on('locationfound', onLocationFound);
mymap.on('locationerror', onLocationError);

...
L.Routing.control({
waypoints: [
L.latLng([self_lat, self_long]),
L.latLng([34.7465, -92.2896])
]
}).addTo(mymap);

如果 self_latself_long 不是全局变量,您将通过仅传递 onLocationFound 的原型来丢失上下文,该函数将在 [= 的上下文中调用14=] 如果这些变量不存在,要解决此问题 并将回调作为单独的函数保存 您可以按如下方式调用它:

mymap.on('locationfound', (e) => onLocationFound(e));

要了解此处的问题,请在 L.Routing.control() 调用之前添加一个 console.log( 'Calling L.Routing.control()', self_lat, self_long ) 调用(代码清单中有 ...)。

您会注意到两件事:

  1. 如您所知,self_latself_long 将在此处 undefined。但是为什么?
  2. 您还将看到这个新的 console.log() 之前被调用 现有的 console.log() 调用在 onLocationFound 中记录这些值功能。这就是问题的根源。

与其他 JavaScript 库和本机 JavaScript 本身中的许多类似功能一样,Leaflet 的 myMap.on( eventName, eventListener ) 功能是 异步的 。这意味着 eventListener - 在这种情况下, onLocationFound - 不会立即被调用。它稍后被调用, myMap.on() 调用本身返回后。

JavaScript 中的所有异步 callback/listener 函数都以这种方式工作。设置一个全局变量很少有用,因为问题是代码的各个位得到运行.

在不知道其余代码的情况下,我可能建议的一种可能的修复方法是完全摆脱 self_latself_long 变量,并移动 L.Routing.control() 调用 你的onLocationFound函数中,像这样:

var mymap = L.map('mapid').setView([34.7465, -92.2896], 6);
...
function onLocationFound(e) {
    console.log(e);
    L.marker(
        [e.latitude, e.longitude],
        {icon: home_marker}
    ).bindPopup("YOU ARE HERE!").addTo(mymap);

    L.Routing.control({
        waypoints: [
            L.latLng([e.latitude, e.longitude]),
            L.latLng([34.7465, -92.2896])
        ]
    }).addTo(mymap);
}

function onLocationError(e) {
    alert(e.message);
}
mymap.locate({setView: false, maxZoom: 16});
mymap.on('locationfound', onLocationFound);
mymap.on('locationerror', onLocationError);

这是一个非常简单的例子,可以帮助说明。我们进行了一个 setTimeout() 调用和三个 console.log() 调用:一个在回调之前,一个之后,一个在回调中。单击下面的 运行 按钮并注意日志消息的顺序:

console.log( 'Before setTimeout' );
setTimeout(
    function() {
        console.log( 'Inside setTimeout callback' );
    },
    1  // one millisecond delay
);
console.log( 'After setTimeout returns' );

当然setTimeout()这个名字更明确了回调函数调用之前会有延迟(哪怕只是一毫秒)。需要注意的是所有异步回调函数和JavaScript中的事件监听器都是这样工作的。