我对地理位置和javascript变量范围有疑问。 我一直在玩弄它,但我是个骗子,js不是我最好的语言。我正在制作谷歌地图,我想将用户坐标设置为地图中心并设置缩放。如果请求失败/被拒绝,那么我正在访问一个Web服务,以从IP获取他们的近似坐标。我想从getLocation()函数中获取位置/缩放,但我无法从navigator.geolocation.getCurrentPosition()获取信息
我已经尝试从错误和位置函数中返回对象,但看起来它没有为此设置,我无法得到任何回复但错误代码。我以为我可以设置var然后覆盖它但是我不能让它返回任何但未定义的东西,我仍然没有100%理解范围并且提升到足以找到解决方案。
geolocFail()按预期工作,正确返回对象。由于它是从navigator.geolocation.getCurrentPosition中的错误函数调用的 - 我无法从那里获取信息。
function getLocation() {
var mapLocation;
if (navigator.geolocation) {
var location_timeout = setTimeout("geolocFail()", 10000);
navigator.geolocation.getCurrentPosition(
function(position) {
clearTimeout(location_timeout);
mapLocation = {position: position.coords.latitude + "," + position.coords.longitude, zoom:10};
}, function(error) {
clearTimeout(location_timeout);
switch(error.code) {
case error.PERMISSION_DENIED:
alertDiv.innerHTML="<p class='text-danger'>User denied the request for Geolocation.</p>";
break;
case error.POSITION_UNAVAILABLE:
alertDiv.innerHTML="<p class='text-danger'>User Location information is unavailable.</p>";
break;
case error.TIMEOUT:
alertDiv.innerHTML="<p class='text-danger'>The request to get user location timed out.</p>";
break;
case error.UNKNOWN_ERROR:
alertDiv.innerHTML="<p class='text-danger'>An unknown error occurred.</p>";
break;
}
mapLocation = geolocFail();
});
}
else {
// Fallback for no geolocation
alertDiv.innerHTML="<p class='text-danger'>Geolocation is not supported by this browser.</p>";
mapLocation = geolocFail();
}
}
function geolocFail(){
//fallback to webservice
var xmlhttp;
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState==4 && xmlhttp.status==200){
if (typeof callback == "function") {
// apply() sets the meaning of "this" in the callback
callback.apply(xmlhttp);
}
}
}
xmlhttp.open("GET","/map/determineLocation?t=" + Math.random(),true);
xmlhttp.send();
if(this.responseText){
var mapLocation = {position: this.responseText, zoom:10}
}
else{
var mapLocation = {position: "40.0000,-100.0000", zoom:4};
}
return mapLocation;
}
答案 0 :(得分:3)
您的具体问题
您的回调是异步的。虽然它们是在一个地方定义的,但实际上它们不会被远程服务触发。
最好的做法是将响应代码包装在一个函数中,然后在回调函数中调用它来处理响应并设计它,使其不依赖于任何类型的程序流。
使用函数在返回时抓取并响应位置数据,而不是尝试将其分配给变量,然后在调用navigator.geolocation.getCurrentPosition
后立即尝试使用该变量。
此(简化)代码有效:
function respond_to_received_data(position) {
console.log(position);
}
function respond_to_error_data(error) {
console.log(error);
}
mapLocation = navigator.geolocation.getCurrentPosition(
function(position) {
respond_to_received_data(position);
},
function(error) {
respond_to_received_data(error);
}
);
有关异步性的更多信息,请参阅following community wiki resource:
但是,关于范围和悬挂的FYI:
JavaScript范围
JavaScript有两个范围,全局范围和功能范围。在函数外部声明的任何变量(使用var关键字)具有全局范围,即它可以在您的网页中的任何位置使用。在函数内声明的任何变量(同样,使用var关键字)将仅对该函数可用,并且为了在该函数之外使用,必须直接返回,或作为返回函数表达式的一部分返回。
这解释了Javascript中用于将代码包装在一个立即调用且可消耗的匿名函数中的非常常见的模式:
(function() { /* code in controlled scope */ }());
Todd Motto will help you learn more
在Javascript中提升
在任何给定范围内,javascript首先收集范围内使用的变量并首先定义它们,或者使用值,或者如果此时不能使用未定义的值推导出它们。有关提升的更多信息,请参阅Mozilla Dev Network description。
帮助可视化上述内容的示例
这两种行为的组合可以用范围中间的for循环来说明。来自for循环的增量变量将在范围的开头处以未定义的形式访问,并且仍将在范围的末尾可用,设置为循环执行期间的最后一个值。
// globally defined
var glob = 'hi';
(function() {
var j = 4;
console.log(j); // => 4
console.log(glob); // => 'hi'
console.log(inLoop); // => undefined
// NB if this was set to anything not used in the scope then execution would be halted by an 'undefined' error in the code
console.log(i); // => undefined
for (var i = 0; i < 10; i ++)
{
var inLoop = 'xyz';
}
console.log(i); // => 10
console.log(inLoop); // => 10
}());
console.log(glob); // => 'hi'
PS new version of JS has the let keyword为所谓的“块范围”或类似PHP定义变量: - )