0

I have been reading about function closure in google map api. They use the following example:

function initMap() {
        var map = new google.maps.Map(document.getElementById('map'), {
          zoom: 4,
          center: {lat: -25.363882, lng: 131.044922 }
        });

        var bounds = {
          north: -25.363882,
          south: -31.203405,
          east: 131.044922,
          west: 125.244141
        };

        // Display the area between the location southWest and northEast.
        map.fitBounds(bounds);

        // Add 5 markers to map at random locations.
        // For each of these markers, give them a title with their index, and when
        // they are clicked they should open an infowindow with text from a secret
        // message.
        var secretMessages = ['This', 'is', 'the', 'secret', 'message'];
        var lngSpan = bounds.east - bounds.west;
        var latSpan = bounds.north - bounds.south;
        for (var i = 0; i < secretMessages.length; ++i) {
          var marker = new google.maps.Marker({
            position: {
              lat: bounds.south + latSpan * Math.random(),
              lng: bounds.west + lngSpan * Math.random()
            },
            map: map
          });
          attachSecretMessage(marker, secretMessages[i]);
        }
      }

      // Attaches an info window to a marker with the provided message. When the
      // marker is clicked, the info window will open with the secret message.
      function attachSecretMessage(marker, secretMessage) {
        var infowindow = new google.maps.InfoWindow({
          content: secretMessage
        });

        marker.addListener('click', function() {
          infowindow.open(marker.get('map'), marker);
        });
      }
    </script>
    <script async defer
    src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap">
    </script>
html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
      #map {
        height: 100%;
      }
 <div id="map"></div>

They are defining the marker variable in each loop iteration.

Question: Why doesn't the marker declared in previous declaration get overridden by the marker declared in the next loop iteration? Why are multiple markers shown on the map? Since there is only one marker variable, there should be only one `marker shown on the map.

user31782
  • 7,087
  • 14
  • 68
  • 143
  • Related [How do JavaScript closures work?](http://stackoverflow.com/q/111102/2151050) – Adam Azad Jun 23 '16 at 06:31
  • The marker already has been added to the map when the variable will be overridden in the next iteration. – Dr.Molle Jun 23 '16 at 06:53
  • @Dr.Molle Do you mean that the line `var marker = new google.maps.Marker` adds a marker onto the map and that marker is an altogether different object(say marker2) from the `marker` variable? But then further down the loop we assign infowindow to to `marker` variable. Then how does google api attach this infowindow to marker2 which is altogether different from `marker`? – user31782 Jun 23 '16 at 07:03
  • @AdamAzad How is my question related to function closures? If instead of calling `attachSecretMessage(marker, secretMessages[i])` function I replace it with it's definition, i.e. I directly add `var infowindow = new google.maps.InfoWindow({ content: secretMessage }); marker.addListener('click', function() { infowindow.open(marker.get('map'), marker); });` into the for loop. Why wouldn't the code work? – user31782 Jun 23 '16 at 07:19

3 Answers3

1

marker is a variable and every time loop iterates , a new object is created using new operator

Now every time marker variable gets updated it references to different object ,just variable assignments changes and objects are still in memory

Consider an example

var student = {
marks: 100
}

var student1 = student;
student = {
marks: 200
}

console.log(student1.marks); //100
console.log(student.marks); //200

See obects are still in memory only my student variable reference changes

Piyush.kapoor
  • 6,715
  • 1
  • 21
  • 21
  • There might many objects, created with the new constructor, in the memory. But after all loop iterations there will be only one `marker` object. And all the infowindows were attached to the `marker` object. So why isn't only one `marker` shown with only one infowindow? – user31782 Jun 23 '16 at 06:48
  • 2
    There is only one `marker` **variable**, but many `google.map.Marker` **objects**. – Stig Hemmer Jun 23 '16 at 07:14
  • @user31782 marker variable gets reassigned to new javascript object every time loop runs. Objects are still in memory . – Piyush.kapoor Jun 23 '16 at 07:20
  • @StigHemmer Sorry, I forget it was a constructor function which I used in `var marker = new google.map.marker`. But if there are many google.map.Marker objects. Then there should be many `google.maps.InfoWindow` objects too. But then why does one `google.maps.InfoWindow` hide when another `google.maps.InfoWindow` is shown? – user31782 Jun 23 '16 at 07:36
  • @StigHemmer In the above comment, I mean if instead of defining each infowindow in every loop iteration I define `var infowindow;` outside of the loop then inside the loop I use `infowindow = new google.maps.InfoWindow()` there should be many google.maps.InfoWindow objects too. But then why does one google.maps.InfoWindow hide when another google.maps.InfoWindow is shown? – user31782 Jun 23 '16 at 07:41
1

Marker still gets overridden, but for this case it doesn't matter because they're not referring to those objects again. I can declare a variable within a loop, then perform an action right after, but as long as I don't need to refer to each individual object outside of the loop they should still serve their purpose, which in this case is to display the markers and show a secret message. For example, in the code below I use the same variable to make 5 buttons, and once I hover them each will alert me that I have hovered.

var buttons = ['button1', 'button2', 'button3', 'button4', 'button5'];

    for(var i = 0; i < buttons.length; ++i)
    {
        var btn = document.createElement("BUTTON");
        var t = document.createTextNode(buttons[i]);
        btn.appendChild(t);           
        document.body.appendChild(btn); 
        hover(btn, buttons[i]);
    } 

    function hover(thing,text)
    {
        thing.addEventListener('mouseover',function(){alert("hovered over "+ text);});
    }
Bryant R.
  • 21
  • 3
  • If instead of calling the function inside loop we add `btn.addEventListener('mouseover',function(){alert("hovered over "+ text);});`. Would that work for each button? – user31782 Jun 23 '16 at 07:20
  • It would be written as `btn.addEventListener('mouseover',function(){alert("hovered over " + buttons[i]);});` but unfortunately the alert says "hovered over undefined," but in the example you gave the attachSecretMessages() is a function outside the loop that is passed a marker with a random location and a different secret message. The way they do it works and there is no need to declare different objects to achieve their goal. – Bryant R. Jun 23 '16 at 07:45
  • It says `"hovered over undefined,"` because in `alert("hovered over " + buttons[i])` `i` is undefined because by the time eventlistener executes the function the loop has already been run. I think it has something to do with function closures. I don't understand why does `text` get the actual values when defined in a `function hover` but `buttons[i]` doesn't when eventlistener is used inline. – user31782 Jun 23 '16 at 07:54
  • I think this older post can explain better then I can http://stackoverflow.com/questions/19586137/addeventlistener-using-for-loop-and-passing-values – Bryant R. Jun 23 '16 at 08:34
0

Hi I thought this problem before. Sometime I have to pass specific parameter from the marker, so I put the marker into array and control the marker by index. This is my code snipped.

  var markersArray = []; //goolge map array
        function GmapCreateMaker(index, x, y, content, iconurl) { //creat Goole map icon
            var myLatlng = new google.maps.LatLng(y, x);
            var marker = new google.maps.Marker({
                position: myLatlng,
                map: map
            });
            markersArray.push(marker);
            if (index == alldataarr.length - 1) {//Check All GMAP ICON ARE PUT INTO ARRAY
                showOverlays();
            }
        }
        function showOverlays() {  //put gmap icon on map
            for (i in markersArray) {
                markersArray[i].setMap(map);
            }
        }
yu wayne
  • 40
  • 2