0

I'm new to JavaScript and I am trying to create a MapManager class that instantiates a few other Managers that will manage different aspects of a Google map; such as markers, different views, etc.

The problem that I am having is that when I attempt to pass "this" as a parameter to the other classes, that the MapManager is instantiating, it only passes an empty instance of MapManager (The JavaScript console shows "MapManager { }" and I get errors when calling the functions declared inside of the MapManager class.)

var MapManager = function(map) {

    var markerManager = new MarkerManager(this);
    var viewManager = new ViewManager(this);

    var getMarkerManager = function() {
        return markerManager;
    }

    var getViewManager = function() {
        return viewManager;
    }

    var getMap = function() {
         return map;
    } 

    return {
        getMarkerManager: getMarkerManager,
        getViewManager: getViewManager,
        getMap: getMap
    }

}

var MarkerManager = function(mapManager) {

    var map = mapManager.getMap();
    var markers = {};

    var createMarker = function(id, latitude, longitude) {

        var marker = new google.maps.Marker({
        position: new google.maps.LatLng(latitude, longitude),
        map: map,
        animation: google.maps.Animation.DROP
        });

        marker.set("id", id);
        markers[id] = marker;

        var listener = new google.maps.event.addListener(marker, "click", function () {
             mapManager.getViewManager().setZoomToClient(id);
        };
    };

    return {
        createMarker: createMarker
    };
}

var ViewManager = function(mapManager) {

    var map = mapManager.getMap();
    var setBoundView = function() {
    var bounds = new google.maps.LatLngBounds();
    var markers = mapManager.getMarkerManager.getMarkers();
    for(id in markers) {
    bounds.extend(markers[id].getPosition());
    }
    map.fitBounds(bounds);
    };

    return {
    setBoundView: setBoundView
    };
}

Am I not able to pass "this" in JavaScript for Dependency Injection? If you are able to compare the differences between "this" in JavaScript as opposed another language then it may be useful to know that I am familiar with PHP, Java and Python.

Kara
  • 6,115
  • 16
  • 50
  • 57
Bradley
  • 1
  • 1
  • 3
  • Doesn't solve your problem but shows you how to use prototype and why. JS doesn't realy support private variables and I normally stay away from the patterns that use them. Can have "private" methods on the prototype but I never used them either: http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Aug 28 '13 at 00:28

1 Answers1

2

The problem that you're having is that the this you're using in your constructor is not actually the thing that you end up constructing. You're using a particular Javascript pattern (that you've probably read about as a good way to implement "private" members) that causes weird things to happen when you try to use some features of the language. [0]

During your constructor's execution, this is actually pointed at an instance of MapManager. However, because you are returning an object from the constructor, your external references to your MapManager instance are references to the returned object, which is not the same as the this that you had referenced in your constructor.

There are a couple of ways to work around this:

  1. If you just remove the return { ... }; from your constructors and replace the assignments you were doing in that object to e.g., this.functionName = functionName;, you should be fine.

  2. If you want to do it in a more standard JavaScriptish way, you can put map on this and put your methods on MapManager.prototype. This SO question explains how to do this, and more about the difference between these two option.

Additionally, if you're interested in a lightweight library that makes defining classical-OO classes easier, I'd suggest taking a look at Classy.

[0] I'm somewhat opinionated on this pattern: I think that it is evil, vile, and broken and should never be used. It breaks fundamental aspects of the language (like prototype chains) in particularly frustrating ways.

Community
  • 1
  • 1
pkh
  • 3,639
  • 1
  • 23
  • 18
  • Agree with the pattern being evil. Try to clone such objects (everything defined with var can only be accessed in the instance). Try to inherit, override and call super.someMethod (it's a pain). It uses more CPU to create and more memory to store. All this trouble just to have private instance varialbes (can do "private" functions in JS when you set prototype with a function returning closures but it's heavier). I would not use "private" but just mark them with `_somePrivate` – HMR Aug 28 '13 at 00:22
  • This is exactly what I do -- make it ugly (and well-known to be private) and people are much less likely to use it. If they do use it (and they may have good reasons for doing so), they'll at the very least know that they're doing so against recommendation. – pkh Aug 29 '13 at 17:58