Binding vs partial application

The difference between JavaScript context binding and partial argument application.

JavaScript has Function.prototype.bind that does two different things: it can bind the function's context to an object, and it can fill arguments with given values from left to right. It helps to think about these two features separately for clarity.

I say "it can" because each feature can be used independently.

Binding context

JavaScript methods can be passed around, and called separately from the original owner object. For example this works just fine

1
2
3
4
5
6
7
var calc = {
add: function (a, b) {
return a + b;
}
};
var addition = calc.add;
console.log(addition(2, 3)); // 5

What if the method add inside calc referenced another property of its owner object? By passing just the reference to the function, we are losing the context

1
2
3
4
5
6
7
8
9
10
11
12
var calc = {
add: function (a, b) {
return a + b;
},
sub: function (a, b) {
return this.add(a, -b);
}
};
// works fine
console.log(calc.sub(10, 1)); // 9
var subtraction = calc.sub;
console.log(subtraction(5, 4));

The last line gets us a TypeError

return this.add(a, -b);
                ^
TypeError: Object #<Object> has no method 'add'

The problem is that when we run the function directly subtraction the value of this is set to undefined in the strict mode. Without strict mode, it is set to the global object (window in the browser). We could run the function and provide the original object reference manually

1
console.log(subtraction.call(calc, 5, 4)); // 1

This gets tiresome very quickly. Instead of specifying the context at the time of the call, we can bind the context to the function beforehand.

1
2
var minus = calc.sub.bind(calc);
console.log(minus(5, 4)); // 1

The function minus has its this variable set to the calc object. We could do interesting things, for example binding the method to another object. As long as it has a method named add the call should still work (but the result might not be correct arithmetic!).

1
2
3
4
5
6
7
8
var badCalc = {
add: function (a) {
return a + 1;
}
};
var wrongMinus = calc.sub.bind(badCalc);
console.log(calc.sub(10, 1)); // 9
console.log(wrongMinus(5, 4)); // 6

When binding a method, we are creating a new function. In the example above, the object's method invocation calc.sub(10, 1) still works correctly. It is not affected by binding the context when creating wrongMinus function.

Partial application

Another thing Function.prototype.bind performs is prefilling the arguments from left to right with given values. Let us create a function that uses our calc object to increment a number by 1.

1
2
3
var increment = calc.add.bind(calc, 1);
// increment is a function eq. to calc.add(1, b)
console.log(increment(7)); // 8

Notice that we used calc as the first argument to the bind call, this is due to bind signature - the context is always the first argument. The values to bind follow at position 2, 3, etc.

We can even fill all arguments or provide more values that the method requires (the extra values will be ignored)

1
2
var ten = calc.add.bind(calc, 6, 4);
console.log(ten()); // 10

Keeping the context

If you are happy with the function's current context, and only need to do partial application, you can pass undefined or null as the first argument to the Function.prototype.bind. For example, calc.add works fine by itself

1
2
var eleven = calc.add.bind(null, 9, 2); // 11
console.log(eleven());

Same with previously bound functions - we can partially apply arguments without knowing and changing the current context.

1
2
3
var minus = calc.sub.bind(calc);
var minuOne = minus.bind(null, 0, 1);
console.log(minuOne()); // -1