How to avoid bind(this) on every function?

1.4k views Asked by At

I'm implementing a web map client built on top of OpenLayers3 which should be able to connect to multiple WMS servers, ask for WMS Capabilities and show layers advertised by servers.

var MyMapClient = function(params) {
    this.wms_sources_ = params.wms_sources;
    this.wms_capabilities_ = [];
}

MyMapClient.prototype.parse_capabilities = function(index) {
    var capabilities = this.wms_capabilities_[index];
    // do something with capabilities 
}

MyMapClient.prototype.load_wms_capabilities = function() {
    var parser = new ol.format.WMSCapabilities();

    jQuery.each(this.wms_sources_, (function (index, wms_source) {

        console.log("Parsing " + wms_source.capabilities_url);

        jQuery.when(jQuery.ajax({
            url: wms_source.capabilities_url,
            type: "GET",
            crossDomain: true,
        })).then((function (response, status, jqXHR) {
            var result = parser.read(response);
            console.log("Parsed Capabilities, version " + result.version);
            this.wms_capabilities_[index] = result;
            return index;
        }).bind(this)).then(this.parse_capabilities.bind(this));

    }).bind(this));
};

The code above works fine but I have to bind(this) every time I want to call a function which needs access to "private" variables of MyMapClient's instance. Isn't there a better way to access instance internals consistently, without sacrificing readability?

2

There are 2 answers

5
Matteo Tassinari On BEST ANSWER

I would say to use the best of both worlds, that is, a local variable holding the correct scope, and calls to bind() where needed:

MyMapClient.prototype.load_wms_capabilities = function() {
    var parser = new ol.format.WMSCapabilities(),
        _this = this;

    jQuery.each(this.wms_sources_, function (index, wms_source) {
        console.log("Parsing " + wms_source.capabilities_url);

        jQuery.when(jQuery.ajax({
            url: wms_source.capabilities_url,
            type: "GET",
            crossDomain: true,
        })).then(function (response, status, jqXHR) {
            var result = parser.read(response);
            console.log("Parsed Capabilities, version " + result.version);
            _this.wms_capabilities_[index] = result;
            return index;
        }).then(
          function() { return _this.parse_capabilities(); }
          // or else
          // _this.parse_capabilities.bind(_this)
          // pick the one you like more
        );
    });
};
2
deceze On

You can "hard bind" a method like this:

function Foo() {
    this.bar = this.bar.bind(this);
}

Foo.prototype.bar = function() {
    return console.log(this.baz);
};

Incidentally, that's what CoffeeScript compiles to when doing this:

class Foo
  bar: =>
    console.log @baz

The => operator causes this preservation of context.