JavaScript gotcha for Pythonistas: bound methods

October 28th, 2013 at 6:09 am

Today while writing some JavaScript code I ran into an interesting gotcha I wanted to briefly mention. It has to do with method binding; more specifically, the behavior I’m used to from Python. Here’s a code sample:

class MyKlass:
    def __init__(self):
        self.num = 2

        f = self.foo
        self.result = f(10)

    def foo(self, othernum):
        return self.num + othernum

mk = MyKlass()
print(mk.result)

The interesting part is invoking self.foo indirectly via f(). This works and prints 12 as expected. It works because the assignment f = self.foo assigns a bound method to f. By "bound", I mean that the method knows which object it belongs to, and when its body is executed self is set to the right thing.

The same does not hold in JavaScript. Here’s a straightforward translation:

'use strict';

var MyKlass = function() {
  this.num = 2;

  var f = this.foo;
  this.result = f(10);
}

MyKlass.prototype.foo = function(othernum) {
  return this.num + othernum;
}

var mk = new MyKlass();
console.log(mk);

This doesn’t work. I get an error from Node.js:

  return this.num + othernum;
             ^
TypeError: Cannot read property 'num' of undefined

So what’s going on? The reason is that, unlike in Python, the assignment f = this.foo does not assign a bound method to f. It’s simply a property lookup on the object this; it indeed has the property foo, which is a function. f now refers to that function. That’s it. There is no implicit binding going on.

Once the problem is understood, it’s easy to solve. The most direct solution is to bind the method explicitly on assignment, using Function.prototype.bind:

var bound_f = this.foo.bind(this);
this.result = bound_f(10);

An alternative solution is not to bind foo when a new reference to it is made, but do it when it’s invoked through that reference. This can be done using Function.prototype.call (or equivalently using its cousin apply):

var f = this.foo;
this.result = f.call(this, 20);

This difference between the two languages exists because unlike Python, JavaScript does not have a first-class entity for a bound method. This is not surprising, because the Python method is bound to an instance, but instances in the "classical" sense don’t exist in JavaScript (see how the class and method concepts from "classical OO" are simulated above with JS’s constructor functions and prototypal inheritance).

What does exist in JavaScript is lexical binding and closures. While the bind method is new in ES5, its effect can be simulated very easily:

Function.prototype.bind = function(obj) {
  var self = this;
  return function () {
    return self.apply(obj, arguments);
  };
}

Note that the actual implementation of bind would be just a little more complicated because bind also supports partial application of arguments (some of the arguments can be provided during binding, and the rest on invocation).

Related posts:

  1. Free and bound variables in Lisp
  2. Python – paralellizing CPU-bound tasks with concurrent.futures
  3. Understanding Ruby blocks, Procs and methods
  4. Python – parallelizing CPU-bound tasks with multiprocessing
  5. Regex-based lexical analysis in Python and Javascript

5 Responses to “JavaScript gotcha for Pythonistas: bound methods”

  1. EricNo Gravatar Says:

    Is it advantageous to call instance (non-”@staticmethod”) methods within a Python object’s class constructor?

  2. elibenNo Gravatar Says:

    @Eric, I hope I understood your question correctly, but I don’t think this matters here at all. It’s merely an example – don’t read too much into it in terms of Python programming style.

  3. JopythonNo Gravatar Says:

    Coffeescript can provide a easy path to javascript for pythonistas.

    class MyKlass
       constructor: ()->
            @num = 2
            f = @foo
            @result = f 10
    
       foo: (othernum)=>
           @num + othernum 
    
    mk = new MyKlass
    console.log mk.result

    Which equates to:

    var MyKlass, mk,
      __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
    
    MyKlass = (function() {
      function MyKlass() {
        this.foo = __bind(this.foo, this);
        var f;
        this.num = 2;
        f = this.foo;
        this.result = f(10);
      }
    
      MyKlass.prototype.foo = function(othernum) {
        return this.num + othernum;
      };
    
      return MyKlass;
    
    })();
    
    mk = new MyKlass;
    
    console.log(mk.result);
  4. EricNo Gravatar Says:

    It’s cool, it’s just a behavior that I might expect to be undefined in most programming languages / environments so I wouldn’t get in the habit of trying to use. I was wondering if there’s a compelling example you have of why you might want to do this?

  5. elibenNo Gravatar Says:

    @Eric,

    It’s a very useful pattern, e.g. when you want to prepare a dispatch table of methods.

Leave a Reply

To post code with preserved formatting, enclose it in `backticks` (even multiple lines)