Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid bind(this) on every function?

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?

like image 267
Peter Kovac Avatar asked Jun 18 '15 10:06

Peter Kovac


People also ask

What's an alternative way to avoid having to bind to this in event callback methods?

Avoid binding by using the public class fields syntax, or bind your callbacks inside the constructor.

Why we dont need to bind this in arrow function?

Why? Because, arrow functions do not bind their own this, instead, they inherit the one from the parent scope or lexical scope. So, it inherited the value of this from App component and that's why there is not need to explicitly bind it.

What is the alternative of binding this in the constructor?

First Method: We can use an arrow function in the render method where we are attaching the event handler. There is one performance implication in this method i.e. whenever the component re-renders the function will be created again and again.

Why do we need to bind a function?

bind(something) returns a new function, in which references to this will refer to something . This is a way of saving the current value of this , which is in scope during the call to the constructor, so that it can be used later when the function is called.


2 Answers

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
        );
    });
};
like image 125
Matteo Tassinari Avatar answered Sep 21 '22 13:09

Matteo Tassinari


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.

like image 27
deceze Avatar answered Sep 22 '22 13:09

deceze