DIY — Function.prototype.bind() in Javascript
I often find it difficult to memorize the purpose of various built-in functions in Javascript. What usually helps is to understand their inner mechanics, sort of an algorithm of how I would implement a function. Here’s an attempt to do so for Function.prototype.bind()
method.
Let’s understand how it works by looking at some examples.
// Let's define a simple sum function.
var sum = (a, b) => a + b;// Let's BIND the first parameter to value 5.
var sum5 = sum.bind(null, 5);// So, now sum5 is a new function and you need to pass only one value to it.
sum5(10); // -> Returns 15
sum5(15); // -> Returns 20// Let's try something else.
var sum10 = sum.bind(null, 10);
sum10(10); // -> Returns 20
sum10(100); // -> Returns 110
You get the point.
Here’s how MDN describes the function:
The
bind()
method creates a new function that, when called, has itsthis
keyword set to the provided value, with a given sequence of arguments preceding any provided when the new function is called.
So by invoking sum.bind(null, 10)
we get a function that has its this
value bound to null
and the first parameter bound to 10
.
Let’s look at another example to get a better idea.
var sum = (a, b, c) => a + b + c;var sum_5 = sum.bind(null, 5);
sum_5(10, 20); // -> Returns 35var sum_5_10 = sum_5.bind(null, 10);
// OR
// var sum_5_10 = sum.bind(null, 5, 10);sum_5_10(20); // -> Returns 35// You can even bind the third parameter.
var sum_5_10_20 = sum_5_10.bind(null, 20);
sum_5_10_20(); // -> Returns 35
Let’s ignore the first argument of the function for a while. I will focus on trying to replicate the behavior of the remaining part.
Binding for functions having two parameters
Let’s create a separate function customBind
and assign to to Function.prototype
object so that it may be used in a fashion similar to Function.prototype.bind()
.
// param1 is the first parameter of the function that takes two arguments.
// I will skip the implementation of `thisArg` for now.
Function.prototype.customBind = function(thisArg, param1) { // `this` points to the function on which we call customBind method.
// `that` saves a reference to `this` such that it may be accessible in functions below through a closure.
var that = this;
// Need to return a function that takes the second parameter, and returns the sum of first parameter and second parameter.
return function(param2) { // Invoke the original function passing the first and the second parameter, and return the result.
return that(param1, param2);
}
}
Let’s try it out with our sum
function.
var sum5 = sum.customBind(null, 5);
sum5(10); // -> Returns 15
Working with any number of parameters
We can make the customBind
function work for three or more parameters with little effort:
Function.prototype.customBind = function(thisArg, param1) {
var that = this; return function() {
// `arguments` is an array like object that gets all arguments passed to this function call.
// `...arguments` will expand the remaining arguments, and pass into the original function as it is being invoked.
return that(param1, ...arguments);
}
}
It is worth noting the two concepts at play here:
- First is
arguments
: It contains the list of all arguments passed to the function call. This allows us to bind to a function having any number of parameters. - Second is destructuring assignment: It allows us to pass all arguments into the function from 2nd position onward.
Let’s try it out:
var sum = (a, b, c) => a + b + c;var sum5 = sum.customBind(null, 5);
sum5(10, 15); // -> Returns 30// Going one step further.
var sum5_10 = sum5.customBind(null, 10);
sum5_10(15); // -> Returns 30
Passing multiple parameters to the bind
function
There is still a problem. With bind
we can get sum5_10
directly from sum
function — without having to call bind
twice. We cannot do that with the customBind
function.
var sum = (a, b, c) => a + b + c;// Binding two arguments using `bind`.
var sum5_10 = sum.bind(null, 5, 10);
sum5_10(15); // -> Returns 30// Binding two arguments using `customBind`.
sum5_10 = sum.customBind(null, 5, 10);
sum5_10(15); // -> Returns NaN
This little problem can also be fixed by using arugments
and destructuring assignment:
Function.prototype.customBind = function(thisArg, ...params) {
var that = this; return function(...otherParams) { // Pass first N parameters, followed by following K parameters.
return that(...params, ...otherParams);
}
}
Let’s try it out with the sum
function that accepts 3 parameters:
var sum = (a, b, c) => a + b + c;
var sum5_10 = sum.customBind(null, 5, 10);
sum5_10(15); // -> Returns 30
sum5_10(5); // -> Returns 20
It also works with a function that accepts 4 parameters:
var sum = (a, b, c, d) => a + b + c + d;
var sum5_10 = sum.customBind(null, 5, 10);
sum5_10(15, 20); // -> Returns 50
sum5_10(5, 10); // -> Returns 30
Just for fun, let’s have a function that will return the sum of any number of arguments, and see if the customBind
function works with that.
var sum = function() {
// See the following if you are not familiar with Array.prototype.reduce: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce return Array.from(arguments)
.reduce((a, b) => a + b);
}sum(5, 10); // -> Returns 15
sum(5, 10, 15); // -> Returns 30
sum(5, 10, 15, 20); // -> Returns 50var sum5 = sum.customBind(null, 5);
sum5(10); // -> Returns 15
sum5(10, 15); // -> Returns 30var sum5_10 = sum.customBind(null, 5, 10);
sum5_10(5); // -> Returns 20
sum5_10(5, 10); // -> Returns 30
sum5_10(5, 10, 15); // -> Returns 45
That’s it for now! I will try to cover the implementation of thisArg
— the first argument passed into bind
function sometime in future.
Hope this helps.