Understanding JavaScript’s Function.prototype.bind

Advertisement

Function binding is most probably your least concern when beginning with JavaScript, but when you realize that you need a solution to the problem of how to keep the context of this within another function, then you might not realize that what you actually need is Function.prototype.bind().

The first time you hit upon the problem, you might be inclined to set this to a variable that you can reference when you change context. Many people opt for self, _this or sometimes context as a variable name. They’re all usable and nothing is wrong with doing that, but there is a better, dedicated way.

Jack Archibald tweets about1 caching this:

It should have been more apparent to me when Sindre Sorhus spelled it out3:

I ignored this wise advice for many months.

What Problem Are We Actually Looking To Solve?

Here is sample code in which one could be forgiven for caching the context to a variable:

var myObj = {

    specialFunction: function () {

    },

    anotherSpecialFunction: function () {

    },

    getAsyncData: function (cb) {
        cb();
    },

    render: function () {
        var that = this;
        this.getAsyncData(function () {
            that.specialFunction();
            that.anotherSpecialFunction();
        });
    }
};

myObj.render();

If we had left our function calls as this.specialFunction(), then we would have received the following error:

Uncaught TypeError: Object [object global] has no method 'specialFunction'

We need to keep the context of the myObj object referenced for when the callback function is called. Calling that.specialFunction() enables us to maintain that context and correctly execute our function. However, this could be neatened somewhat by using Function.prototype.bind().

Let’s rewrite our example:

render: function () {

    this.getAsyncData(function () {

        this.specialFunction();

        this.anotherSpecialFunction();

    }.bind(this));

}

What Did We Just Do?

Well, .bind() simply creates a new function that, when called, has its this keyword set to the provided value. So, we pass our desired context, this (which is myObj), into the .bind() function. Then, when the callback function is executed, this references myObj.

If you’re interested to see what Function.prototype.bind() might look like and what its doing internally, here is a very simple example:

Function.prototype.bind = function (scope) {
    var fn = this;
    return function () {
        return fn.apply(scope);
    };
}

And here is a very simple use case:

var foo = {
    x: 3
}

var bar = function(){
    console.log(this.x);
}

bar(); // undefined

var boundFunc = bar.bind(foo);

boundFunc(); // 3

We’ve created a new function that, when executed, has its this set to foo — not the global scope, as in the example where we called bar();.

Browser Support

Browser Version support
Chrome 7
Firefox (Gecko) 4.0 (2)
Internet Explorer 9
Opera 11.60
Safari 5.1.4

As you can see, unfortunately, Function.prototype.bind isn’t supported in Internet Explorer 8 and below, so you’ll run into problems if you try to use it without a fallback.

Luckily, Mozilla Developer Network, being the wonderful resource it is, provides a rock-solid alternative7 if the browser hasn’t implemented the native .bind() method:

if (!Function.prototype.bind) {
  Function.prototype.bind = function (oThis) {
    if (typeof this !== "function") {
      // closest thing possible to the ECMAScript 5 internal IsCallable function
      throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
    }

    var aArgs = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP = function () {},
        fBound = function () {
          return fToBind.apply(this instanceof fNOP && oThis
                                 ? this
                                 : oThis,
                               aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
  };
}

Patterns For Usage

When learning something, I find it useful not only to thoroughly learn the concept, but to see it applied to what I’m currently working on (or something close to it). Hopefully, some of the examples below can be applied to your code or to problems you’re facing.

Click Handlers

One use is to track clicks (or to perform an action after a click) that might require us to store information in an object, like so:

var logger = {
    x: 0,
    updateCount: function(){
        this.x++;
        console.log(this.x);
    }
}

We might assign click handlers like this and subsequently call the updateCount() in our logger object:

document.querySelector('button').addEventListener('click', function(){
    logger.updateCount();
});

But we’ve had to create an unnecessary anonymous function to allow the this keyword to stand correct in the updateCount() function.

This could be neatened up, like so:

document.querySelector('button').addEventListener('click', logger.updateCount.bind(logger));

We’ve used the subtly handy .bind() function to create a new function and then set the scope to be bound to the logger object.

setTimeout

If you’ve ever worked with templating engines (such as Handlebars) or especially with certain MV* frameworks (I can only speak of Backbone.js from experience), then you might be aware of the problem that occurs when you render the template but want to access the new DOM nodes immediately after your render call.

Suppose we try to instantiate a jQuery plugin:

var myView = {

    template: '/* a template string containing our <select /> */',

    $el: $('#content'),

    afterRender: function () {
        this.$el.find('select').myPlugin();
    },

    render: function () {
        this.$el.html(this.template());
        this.afterRender();
    }
}

myView.render();

You might find that it works — but not all the time. Therein lies the problem. It’s a rat race: Whatever happens to get there first wins. Sometimes it’s the render, sometimes it’s the plugin’s instantiation.

Now, unbeknownst to some, we can use a slight hack8 with setTimeout().

With a slight rewrite, we can safely instantiate our jQuery plugin once the DOM nodes are present:

//

    afterRender: function () {
        this.$el.find('select').myPlugin();
    },

    render: function () {
        this.$el.html(this.template());
        setTimeout(this.afterRender, 0);
    }

//

However, we will receive the trusty message that the function .afterRender() cannot be found.

What we do, then, is throw our .bind() into the mix:

//

    afterRender: function () {
        this.$el.find('select').myPlugin();
    },

    render: function () {
        this.$el.html(this.template());
        setTimeout(this.afterRender.bind(this), 0);
    }

//

Now, our afterRender() function will execute in the correct context.

Tidier Event Binding With querySelectorAll

The DOM API improved significantly once it included such useful methods as querySelector, querySelectorAll and the classList API, to name a few of the many.

However, there’s not really a way to natively add events to a NodeList as of yet. So, we end up stealing the forEach function from the Array.prototype to loop, like so:

Array.prototype.forEach.call(document.querySelectorAll('.klasses'), function(el){
    el.addEventListener('click', someFunction);
});

We can do better than that, though, with our friend .bind():

var unboundForEach = Array.prototype.forEach,
    forEach = Function.prototype.call.bind(unboundForEach);

forEach(document.querySelectorAll('.klasses'), function (el) {
    el.addEventListener('click', someFunction);
});

We now have a tidy method to loop our DOM nodes.

Conclusion

As you can see, the .bind() function can be subtly included for many different purposes, as well as to neaten existing code. Hopefully, this overview has given you what you need to add .bind() to your own code (if necessary!) and to harness the power of transforming the value of this.

(al, il)

Footnotes

  1. 1 https://twitter.com/jaffathecake/status/304163675810439168
  2. 2 https://twitter.com/jaffathecake/statuses/304163675810439168
  3. 3 https://twitter.com/sindresorhus/status/304917599484010496
  4. 4 https://twitter.com/benhowdle
  5. 5 https://twitter.com/search?q=%24this&src=ctag
  6. 6 https://twitter.com/sindresorhus/statuses/304917599484010496
  7. 7 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
  8. 8 http://benhowdle.im/2013/01/29/settimeout/

↑ Back to topShare on Twitter

Ben Howdle is a web developer from Droitwich, UK. He works by day at Wapple.net and by night and weekends as Two Step Media. An insatiable passion for the dynamic web and exciting web applications.

Advertising
  1. 1

    Thought it might be worth pointing out that the same can be achieved with jQuery’s $.proxy() instead of having to do $this… For example, your button click event would then look like:

    $('button').click($.proxy(logger.updateCount, logger));

    Working example here: http://jsbin.com/ELITIfo/1/edit

    2
  2. 3

    Awesome Article!!!

    This is also kind of nice answer about Inheritance and JS http://bit.ly/1l0Hl43 (stackoverflow)

    0
  3. 4

    Thanks for the great post. There is a typo in “this instance of fNOP”.
    It should be “instanceof”.

    0
    • 5

      Hey Jim,

      Thanks for the kind words and ace spot on the code typo! That was straight from the MDN docs as well, so they also have a typo ; )

      0
  4. 6

    There is much truth in this article. Thanks for the great post.

    But at least for me, there are some cases where using .bind() can cause confusion, as I need to scroll down to the bottom of my functions scope to see that ‘this’ has been overwritten. Especially in more complex projects, I prefer relying on my own, more ‘speaking’ variables.

    Nevertheless, using .bind() appears to be more sexy than that = this; :-)

    0
  5. 7

    Binding is slow in chrome? See this test: http://jsperf.com/binding2

    0
  6. 8

    Nice! Didn’t know about the bind keyword.

    Just out of curiosity – is there anything technically wrong with using that = this? Any gotchya’s we should be aware of?

    0
    • 9

      Hey Sean, nope, nothing technically wrong, just means a (potentially unnecessary) extra line of code when there’s a native solution available!

      0
      • 10

        Richard Korebrits

        February 4, 2014 12:03 am

        Hi Ben,
        This is what I don’t really get out of your article. Either use that = this (I prefer t = this) once, or you need to use `bind()` every time. How is using t = this “a (potentially unnecessary) extra line”, whereas using `bind` more than once means multiple extra lines.

        I see that in some cases it might be handy, but there is e.g. no mention of how to use `this` inside of the getAsyncData scope because `this` is set to the parent scope. What if you need to bind to the current scope?

        this.getAsyncData(function () {
        this.specialFunction();
        this.anotherSpecialFunction();
        }.bind(this));

        0
  7. 11

    Wow! This totally blew my mind. And I thought I had somewhat mastered JS :D This will change my patterns significantly. Great post!

    0
  8. 12

    In the “settimeout” section, you wrote: “However, we will receive the trusty message that the function .afterRender() cannot be found.”
    Wouldn’t the message stat that “this.$el” cannot be found instead?

    Great article, by the way.

    0
  9. 15

    Some performance tests? In some cases i revert back to the context variable because explorer hang.

    0
  10. 16

    I ran the basic object with methods and using bind in the render method through jsPerf, it looks like aside from Firefox, using the bind method might be slower. Unless I’m doing something wrong.. http://jsperf.com/prototype-bind-vs-variable-cache/2

    0
  11. 17

    I’m not a huge fan of .bind(). Technically it works fine, but reusing this within multiple nested contexts can cause confusion… using “var self = this;” or something like that creates a clear distinction between objects to avoid confusion as to which this you actually mean. It also avoids problems like in a click handler where you might want to have access to the normal “this” scope as well as your original “this” scope.

    0
    • 18

      Hey Jon,

      Fair points indeed,

      Inside event handlers (click, for example) you can still use the passed in Event object, ie. e.currentTarget

      0
    • 19

      Agreed, 100%. I use self or that to store my this reference for any code that nests and I have never seen a significant enough performance hit to warrant further optimization or an alternate implementation.

      0
  12. 20

    Alexandr Marinenko

    January 23, 2014 9:23 am

    Ben, you defined an object logger and you use bind to solve “this” problem inside of “updateCount”. Why don’t you use “logger.x++” instead of “this.x++”?

    0
    • 21

      Hey Alexandr,

      You’re totally right, we could definitely use `logger.x++`, I’m just pointing out that if you wanted to keep things a bit more reusable/generic then, using `this.x` and not having to explicitly reference `logger` would be a little more preferable…

      -1
  13. 22

    Is it me or does it seem *this* problem is better resolved by passing ‘this’ as the argument to the anonymous function? It’s explicit, doesn’t create a closure, and is one line shorter than the original source.

    var myObj = {
    specialFunction: function () {},
    anotherSpecialFunction: function () {},
    getAsyncData: function (cb, obj) {
    cb( obj );
    },
    render: function () {
    this.getAsyncData( function ( that ) {
    that.specialFunction();
    that.anotherSpecialFunction();
    });
    }
    };
    myObj.render();

    0
    • 23

      Anonymous functions are never the better solution, they make it harder for the engine to optimise code. I have no proof, but I’d imagine that it’d be easier to optimise a function produced by bind that an anonymous function.

      I also prefer to only have to look for the “this” keyword (which editors usually recognise and highlight) rather than also having to search for “self”, “that” or whatever variable you pass it to. That’s just an opinion though!

      -1
  14. 24

    func.bind() is funny !

    But the fun goes on … ever tried something like func.bin(x)() ?

    Using func.call() or func.apply() can also lead to some nice insights into the
    elegance of Javascript

    Regards

    0
  15. 25

    Another solution would be to integrate underscore.js.
    Then you can use:

    render: function () {
    _.bind(this.getAsyncData(function () {
    this.specialFunction();
    this.anotherSpecialFunction();
    }), this);
    }

    0
  16. 26

    It’s a fantastic article!

    I would appreciate if you could elaborate how the following code is better than the previous alternative:
    —-
    var unboundForEach = Array.prototype.forEach,
    forEach = Function.prototype.call.bind(unboundForEach);

    forEach(document.querySelectorAll(‘.klasses’), function (el) {
    el.addEventListener(‘click’, someFunction);
    });
    —–
    Is the former code any faster?

    0
    • 27

      Hi Vasulu,

      Thanks for commenting, the former code probably will be marginally faster as .bind() does involve some minor processing to return a new, bound function. I just feel that the latter example is slightly more readable as you would maybe store the first two lines in a utils.js/helper.js file…

      0
  17. 28

    Fantastic explanation with examples. Keep up the good work.

    0
  18. 29

    The partial implementation creates bound functions whose length property does not agree with that mandated by ECMA-262: it creates functions with length 0, while a full implementation, depending on the length of the target function and the number of pre-specified arguments, may return a non-zero length. http://eduresult.in

    if (!Function.prototype.bind) {
    Function.prototype.bind = function (oThis) {
    if (typeof this !== “function”) {
    // closest thing possible to the ECMAScript 5 internal IsCallable function
    throw new TypeError(“Function.prototype.bind – what is trying to be bound is not callable”);
    }

    var aArgs = Array.prototype.slice.call(arguments, 1),
    fToBind = this,
    fNOP = function () {},
    fBound = function () {
    return fToBind.apply(this instanceof fNOP && oThis
    ? this
    : oThis,
    aArgs.concat(Array.prototype.slice.call(arguments)));
    };

    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();

    return fBound;
    };
    }

    0
  19. 30

    Very nice article, I was facing these kind of issues and I really don’t like this that trick. thanks!

    0
  20. 31

    Something about this article finally made me figure out why I’ve never found `bind()` super intuitive — it’s the fact that it comes _after_ the function body, which means that reading the function body top to bottom you don’t know what `this` means until you get to the end. Hopefully the function body is pretty short to minimize this problem.. but still… While using `var that = this` is clunky, at least you know can read the code linearly and know what is happening.

    Still, `bind()` is the way to go.

    1
  21. 32

    Great article! I discovered .bind() a while ago and haven’t looked back, I’d guess that using it is easier to optimise for the JS engines than an anonymous function. I said this in a reply but I also prefer knowing that I’ve only used “this” to refer to instance variables, editors will highlight it, and I won’t have to worry about searching for “that”, “self” or “context” variables (or forgetting to use the correct one in specific methods).

    The thing that wasn’t mentioned is that any parameters specified after the first one will be applied to the function as its own parameters, so you could create very specific functions out of generic ones.

    For instance (apologies for the stupid example):

    function doubleElementSize(element) {…}
    var doubleTitleSize = doubleElementSize(window, document.getElementsByTagName(“h1″)[0]);

    Would mean you could call doubleTitleSize(); to double the size of the first on the page.

    0
  22. 33

    Great article thanks Ben. Discoveries like this along with my recent understanding of .wrap() have really changed my views on prototype coding (Magento extensions) from “a bit sketchy” to neat and robust implementations.

    0
  23. 34

    Scruffy code! Its not great to do this. A variable has a better performance than a function.

    0
  24. 35

    Can someone explain me why in Mozilla’s rock-solid alternative they write Array.prototype.slice.call(arguments, 1); instead of arguments.slice(1); Why they go through Array.prototype.slice ?!

    0
    • 36

      Hey Vladimir,

      because `arguments` is not a real array, it’s known as ‘array-like’ or a ‘pseudo-array’ it doesn’t have a method called `slice` available. So you call `slice` from the Array.prototype which, inside the `slice` method, refers to `this` as the array-like “arguments”.

      Hope that all makes sense!

      0
  25. 37

    This article is a great help for understanding prototype bind.

    I have been coding in javascript for a while but didn’t realize we can actually bind this instead of using var _this = this.

    0
  26. 38

    It’s an interesting article, and it helped clear up the use of bind for me, thanks.

    From a readability point of view, I don’t buy it. that = this et al strikes me as clearer for the reasons outlined by other posters: top down reading, explicitness.

    0
  27. 39

    Good intro, but I’d suggest to add one more thing, you can append after scope, any argument, and it will be passed to executed function:

    var method = function(one, two, three) {
    console.log(one, two, three);
    };

    method.bind(this, 1, 2, 3)();

    Sometimes it is really useful, when you are working with event listeners, and want to pass something from current context to the new method context.

    0
  28. 40

    if only there was a way to do this with objects, still need it there:

    var a = {
    b: function() {return 1},
    c: function() {
    var that = this;
    var d = {
    e: that.b()
    };

    return d.e;
    }
    }

    0
  29. 41

    Lars Rönnbäck

    March 14, 2014 2:21 am

    Actually, when adding the event handler, using bind() on the callback function as an argument to addEventListener will make it impossible to remove that listener. The bind() function will return a new function everytime it is called, as can easily be seen by the test: alert(alert.bind(this) == alert.bind(this));
    In order to remove the listener, you need to save a reference to the bound function. An uncluttered way to do so is to replace the original function with the bound one, as in this example: http://jsfiddle.net/roenbaeck/vBYu3/

    1
  30. 42

    Dmitry Pashkevich

    April 15, 2014 12:23 pm

    One problem with `bind()` is that it iself creates a new anonymous function that will appear in stack traces.

    0
  31. 43

    Actually, the example for which you say there will be an error, works just fine.

    http://jsfiddle.net/ayMEY/

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top