如何检查数组的对象是在for循环

时间:2018-01-17 16:37:15

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

您好我正在开发一个谷歌地图项目,我正在绘制一个旅程,我正在使用AJAX请求将数据作为一个对象数组返回,然后我循环遍历该数组并创建一个新的latlng对象数组如下所示,这一切都很完美

var pathCoords = [];
for (var i = 0; i < Object.keys(data).length; i++) {
                route = {
                    lat : data[i].latitude,
                    lng : data[i].longitude
                }

                pathCoords.push(route);
            }

我接下来绘制开始和结束标记,这很好,然后我循环遍历pathCoords []并沿折线绘制移动标记。见下面的方法

    for (i = 0; i < pathCoords.length; i++) {
            setTimeout(function(coords) {
                var latlng = new google.maps.LatLng(coords.lat, coords.lng);
                routeLine.getPath().push(latlng);
                moveMarker(map, marker, latlng);
                if(i === (Object.keys(data).length-1)){
                    console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length);
centerMapandZoom(markerStart,markerEnd,pathCoords);
                }

                    //console.log("data link...."+Object.keys(data).length)

            }, 200 * i, pathCoords[i]);

moveMarker执行它所说的操作,移动标记,我想要实现的是调用方法,当for循环结束时调用<{1}} ,此方法相应地适应和集中地图,我已经搜索并尝试了所有内容,并且无法弄清楚这一点,我也尝试了来自其他答案的SO解决方案,这只是不起作用,如下面的方法。

centerMapandZoom(markerStart,markerEnd,pathCoords);

任何帮助或解决方案,我基本上都试图在地图上填写路线和标记,说我尝试使用if(i === (Object.keys(data).length-1)){ console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length); } ,这对我也没帮助,谢谢

4 个答案:

答案 0 :(得分:2)

我会利用Promise.all的承诺来处理这个问题,它看起来像这样:

function delayedMarkerPlace(i) {
    return new Promise(resolve => {
        setTimeout(() => {
            // place the marker
            resolve();
        }, 200 * i)
    });
}

const placeMarkersPromises = [];

for (var i = 0; i < Object.keys(data).length; i++) {
    placeMarkersPromises.push(delayedMarkerPlace(i));
}

Promise.all(placeMarkersPromises).then(() => {
    // action after all markers have been placed
});

答案 1 :(得分:1)

您正在循环中创建一个函数,这意味着i的值是通过引用捕获的,这意味着当执行超时函数时i的值与创建函数时的值不同。

尝试在循环之外创建函数并传递它需要的所有信息,例如:(不,我没有测试过这个,但我希望它可以解决这个问题。)

var on_call = function(coords, j, end_index) {
                var latlng = new google.maps.LatLng(coords.lat, coords.lng);
                routeLine.getPath().push(latlng);
                moveMarker(map, marker, latlng);
                if(j === end_index){
                    console.log("This is the end..."+i+"coordinates size "+end_index + 1);
                    centerMapandZoom(markerStart,markerEnd,pathCoords);
                }
            }
    for (i = 0; i < pathCoords.length; i++) {
            setTimeout(on_call , 200 * i, pathCoords[i], j, pathCoords.length -1);

在循环中创建一个函数是你想要避免很多时间的事情,因为闭包可能会导致一开始看起来很奇怪的错误。

建议阅读:http://javascriptissexy.com/understand-javascript-closures-with-ease/

答案 2 :(得分:1)

因为您已为后续功能

创建了闭包
 for (i = 0; i < pathCoords.length; i++) {
            setTimeout(function(coords) {
                var latlng = new google.maps.LatLng(coords.lat, coords.lng);
                routeLine.getPath().push(latlng);
                moveMarker(map, marker, latlng);
                if(i === (Object.keys(data).length-1)){
                    console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length);
centerMapandZoom(markerStart,markerEnd,pathCoords);
                }

                    //console.log("data link...."+Object.keys(data).length)

            }, 200 * i, pathCoords[i]);
}

这里setTimeout是异步的,所以第一次遇到for循环时, 它将函数放入池中以在超时后执行并继续执行代码,以便循环继续和下一个并且相同直到达到长度,

现在在函数执行超时后,它可以访问外部作用域变量i,现在已经等于长度。在第一次条件检查时

i === (Object.keys(data).length-1) // i is already equals to length-1,

解决方案是使用iife

for (i = 0; i < pathCoords.length; i++) {
             (function(i){
setTimeout(function(coords) {
                    var latlng = new google.maps.LatLng(coords.lat, coords.lng);
                    routeLine.getPath().push(latlng);
                    moveMarker(map, marker, latlng);
                    if(i === (Object.keys(data).length-1)){
                        console.log("This is the end..."+i+"co=ordinates size "+pathCoords.length);
    centerMapandZoom(markerStart,markerEnd,pathCoords);
                    }

                        //console.log("data link...."+Object.keys(data).length)

                }, 200 * i, pathCoords[i]);
}(i))   
    }

link to concept of closure

答案 3 :(得分:1)

在JavaScript中,函数创建自己的执行上下文。因此,每次调用函数时,都会创建一个新的执行上下文。如果您创建一个setTimeout函数,该函数将异步运行,这意味着JavaScript引擎将继续逐行解析并执行您的代码,而无需等待您的计时器函数返回。这意味着您丢失了想要分配给变量i的任何值,只是因为您没有在该特定执行上下文或范围中捕获其值。因此,为了捕获该值,您必须创建一个闭包。使用闭包,您可以将代码包含在一个函数中,创建一个具有自己的执行上下文的本地作用域,从而允许您获取i的值。

for (i = 0; i < pathCoords.length; i++) {
  //  this is how you do not lose the value of i
  //  waiting for setTimeout to return
  (function(i){ 
    // note the above function has a closure over setTimeout
    // this is where the magic happens because here you create the 
    // execution context or local scope you want to "link" the iteration 
    // to the timer function
    setTimeout(function(coords) {
      var latlng = new google.maps.LatLng(coords.lat, coords.lng);
      routeLine.getPath().push(latlng);
      moveMarker(map, marker, latlng);
      if(i === (Object.keys(data).length-1)){
        console.log("This is the end..."+i+"co=ordinates size" +pathCoords.length);
   centerMapandZoom(markerStart,markerEnd,pathCoords);
      }
    }, 200 * i, pathCoords[i]);

  // the IIFE function gets executed and you pass an 
  // argument that will equal i when passed as a parameter
  // inside the IIFE function

  }(i))   
}

在现代浏览器中,您还可以通过将LET声明用作for循环中的变量来创建局部作用域,如下所示:

for (let i = 0; i < whatever.length; i++){
  whatever you want;
}

这意味着您将为您的问题提供更优雅的解决方案,其缺点是旧版浏览器可能不支持。换句话说,它需要测试。你可以为闭包实现其他解决方案,但那些更多&#34;冗长&#34;写作和解释,但如果您需要其他解释或示例,请告诉我。