代码之家  ›  专栏  ›  技术社区  ›  metrallador10

为什么for循环内部的全局变量不改变值?Javascript

  •  0
  • metrallador10  · 技术社区  · 6 年前

    我在执行一个函数时遇到了一个问题,该函数使用3个全局变量运行for循环,这些变量将被传递给回调函数。所有数组的长度都相同,问题在于3个窗口变量,称为in getPickup() 在回调函数内部,不要更改任何循环中的值。我觉得很奇怪,因为这些变量应该从中更新一个新值 location 当回调函数完成,循环再次运行时。

    function calculateDistanceDriverCustomer() {
           {% autoescape off %}
           var locations = {{ locations }}
           {% endautoescape %}
    
           {% autoescape off %}
           var firstname = {{ firstname }}
           {% endautoescape %}
    
           {% autoescape off %}
           var lastname = {{ lastname }}
           {% endautoescape %}
    
           {% autoescape off %}
           var rating = {{ rating }}
           {% endautoescape %}
           var location;
           for (location = 0; location < locations.length; location++) {
            var origin = locations[location];
            window.firstname = firstname[location];
            window.lastname = lastname[location];
            window.rating = rating[location];
            var destination = $('#origin-input').val();
            var service = new google.maps.DistanceMatrixService();
            service.getDistanceMatrix(
                    {
                        origins: [origin],
                        destinations: [destination],
                        travelMode: google.maps.TravelMode.DRIVING,
                        unitSystem: google.maps.UnitSystem.METRIC, // kilometers and meters.
                        avoidHighways: false,
                        avoidTolls: false
                    }, callback);
            }
    };
    
    
    function callback(response, status) {
                if (status != google.maps.DistanceMatrixStatus.OK) {
                    $('#result').html(err);
                } else {
                    var origin = response.originAddresses[0];
                    var destination = response.destinationAddresses[0];
                    if (response.rows[0].elements[0].status === "ZERO_RESULTS") {
                        $('#result').html("Better get on a plane. There are no roads between "  + origin + " and " + destination);
                    } else {
                            //get estimated pickup time if distance less or equal than 10km
                        function getPickup() {
                            var distance = response.rows[0].elements[0].distance;
                            var duration = response.rows[0].elements[0].duration;
                            var distance_in_kilo = distance.value / 1000;
                            var duration_value = duration.value*1000;
                            console.log(distance_in_kilo);
                            var time = new Date()
                            time = new Date(time.getTime() + duration_value);
                            var date = new Date(time)
                            var currenthr = date.getHours()
                            var currentmin = date.getMinutes()
                            var currentsec = date.getSeconds()
                            if (currenthr   < 10) {currenthr   = "0"+currenthr;}
                            if (currentmin < 10) {currentmin = "0"+currentmin;}
                            if (currentsec < 10) {currentsec = "0"+currentsec;}
                            window.pickupTime = currenthr + ":" + currentmin + ":" + currentsec;
                            console.log(pickupTime);
                            if (distance_in_kilo <= 3000) {
                                var name = document.createElement("hd");
                                var brk = document.createElement("br");
                                var node = document.createTextNode(window.firstname + " " + 
                                window.lastname);
                                name.appendChild(node);
                                var element = document.getElementById("cars");
                                element.appendChild(name);
                                element.appendChild(brk);
                                var pickup = document.createElement("hd");
                                var node1 = document.createTextNode("Pickup Time: " + window.pickupTime);
                                pickup.appendChild(node1);
                                var element1 = document.getElementById("cars");
                                element1.appendChild(pickup);
                                element1.appendChild(brk);
                                var rating = document.createElement("hd");
                                var node3 = document.createTextNode("rating: " + window.rating);
                                rating.appendChild(node3);
                                var element3 = document.getElementById("cars");
                                element3.appendChild(rating);
                                element3.appendChild(brk);
                            }
                            else {
                                console.log("Not available");
                            }
    
                         }
                        getPickup();
                    }
                }
            };
    
    

    变量是在for循环的开头定义的,它们是 window.firstname , window.lastname window.rating 。它们从一个数组中获取值,该数组的内容是从python(定义于 calculateDistanceDriverCustomer() . 这是python代码:

     cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute("SELECT CurrentLocation, FirstName, LastName, OverallRating FROM driver WHERE OnJourney=0")
        rows = cursor.fetchall()  # data from database
        locations = []
        firstname = []
        lastname = []
        rating = []
        for row in rows:
            locations.append(row['CurrentLocation'])
            firstname.append(row['FirstName'])
            lastname.append(row['LastName'])
            rating.append(row['OverallRating'])
        return render_template("Search.html", rows=rows, locations=locations, firstname=firstname, lastname=lastname, rating=rating)
    

    谢谢你的帮助

    0 回复  |  直到 6 年前
        1
  •  0
  •   3limin4t0r    6 年前

    我对Django一无所知,但是 getDistanceMatrix 回调调用可能是异步进行的。这意味着在触发第一次回调时,for循环已经完成。使用这些值生成所有回调 window.firstname , window.lastname window.rating 那是 由上一次迭代设置 循环的一部分。

    如果这确实是问题所在,您可以通过将其作为 callback 而不是参数。

    for (let location = 0; location < locations.length; location++) {
      // ^^^ Move the location definition inside the for-loop and use `let` instead
      //     of `var`. This has to do with scoping and might prevent bugs later on.               
      // https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
    
      // Use `const` (or `let`) instead of `var` see link above.
      const data        = {},
            destination = $('#origin-input').val(),
            service     = new google.maps.DistanceMatrixService();
    
      data.origin    = locations[location];
      data.firstname = firstname[location];
      data.lastname  = lastname[location];
      data.rating    = rating[location];
    
      service.getDistanceMatrix(
        {
          origins:       [origin],
          destinations:  [destination],
          travelMode:    google.maps.TravelMode.DRIVING,
          unitSystem:    google.maps.UnitSystem.METRIC, // kilometers and meters.
          avoidHighways: false,
          avoidTolls:    false
        },
        // forward the response and status to the callback and add your data
        (response, status) => callback(response, status, data)
      );
    }
    

    然后在回调中接受这些参数:

    function callback(response, status, data) {
      // ...
      var node = document.createTextNode(`${data.firstname} ${data.lastname}`);
      // ...
    }
    

    我还建议你搬家,比如 new google.maps.DistanceMatrixService() $('#origin-input').val() 在for循环之外。它们不依赖于正在迭代的元素,而是根据需要创建更多的元素。(如果 locations 包含你创建的100个元素 新谷歌。地图。距离矩阵服务() 而你很可能只需要1个。)我在示例代码中忽略了这一点,因为没有必要修复代码。