Search code examples
javascriptthiscallapply

Javascript .call() usage. One working case, one not. What's the diff?


I'm confused at the difference in these usage cases:

   // CASE 1: Two separate attempts, neither work (see comments)

    var circle = new google.maps.Circle({ 
          // and then a bunch of properties, all work fine. Including this to show you 
          // where the variable I'm trying to use in call() came from
    });

    circle.initListeners = function(){
         this.addListener('mouseover', function(){

              // Works if circle is named explicitly in explodeView (see code below), 
              // doesn't work with .call(circle) here, this.setRadius() in explodeView   
              explodeView().call(circle);

              // Both work fine
              this.infoWindow.setPosition(this.getBounds().getNorthEast());
              this.infoWindow.open(map);

              // Works with circle.getCenter, not with .call(circle) and this
              this.timer = setInterval(function(){
                  map.panTo(this.getCenter());
              }, 1000).call(circle)

               // Works with circle.setRadius, not with this.setRadius
               function explodeView(){
                   var radiusExtender = ((300 - tweet.stats.reach) + 1) / 60;
                   radiusExtender > 1.15 ? this.setRadius(radiusExtender * radius) : this.setRadius(radius * 1.15);
               }  
          });
      });

Compare this with the following use of .call(), which I implemented after getting a "this does not have method ._togCircVis(...)" error when invoking the function without .call(map):

   // CASE 2: Works

   // Call to function I added to circle prototype
   map._togCircVis.call(map)

   // Successfully receives map and executes correctly
   google.maps.Map.prototype._togCircVis = function(){
      this.circles.forEach(function(circle){
        circle.getMap() != null ? circle.setMap(null) : circle.setMap(map);
      })
    }     

When I try the code in Case 1, I get the same "this does not have method " error as I did before adding .call(map) to Case 2. Same thing when I try .apply() instead of .call() (a Hail Mary debug attempt). I get why the addition to Case 2 makes it work, as it clarifies for the invoked function that I'm talking about the map object, not the window object, when I use this for variable assignment. But, why doesn't it work with the above cases? MDN articles helped me get to using .call(map), but did not clear up this other use for me. Thanks!


Solution

  • explodeView().call(circle); here you are calling explodeView normally (without call) and then trying to call call on the value it returned (undefined). Instead you should write explodeView.call( circle ). You have a very similar problem here:

    setInterval(function(){
        map.panTo(this.getCenter());
    }, 1000).call(circle);
    

    You are trying to call call on an object that isn't a function. Before it was undefined, this time it is a number (setInterval returns a number). You could use bind like this to achieve what you want:

    setInterval(function(){
        map.panTo(this.getCenter());
    }.bind(circle), 1000);