Functions
JavaScript is powerful in part because functions are first class citizens. They can be passed as arguments to other functions, returned from functions and assigned to variables. The problem is that when passing functions around, the original context is lost. For example:
1 | var foo = { |
We are storing reference to method printName from object foo,
but the assignment looses the ownership context. The value of this
inside the printName has no meaning when called via printer.
In fact, if used exactly like written above, this is bound to window
in the browser (or global in Nodejs). If we used 'use strict';
inside printName or globally, trying to call printer() would
generate an exception TypeError: Cannot read property 'name' of undefined.
I often see a solution to this problem that uses local variables named
that or me and function closures, for example
1 | // inside some object |
Function.bind
Enter Function.bind, part of EcmaScript 5 and available pretty much everywhere
(or through a es5-shim). It creates a new
function that binds this to the object. Same example works as expected
1 | ; |
If you find writing object.methodName.bind(object) too verbose,
I wrote dotdot Node loader hook
that allows shortcut
1 | ; |
Function.bind for partial application
Aside from preserving the right context, I use function.bind to pass
default arguments to the callback function removing temporary or instance variables.
For example:
1 | var numbers = [1, 2, 3, 4]; |
Notice how we use a temporary function to keep passing number 2 to the multiplication
function. We can use bind to bind both context (in this case undefined), and
any number of arguments!
1 | var numbers = [1, 2, 3, 4]; |
In line // 1 we created and returned a new function that passes 2 as first argument
to function mul(a, b). We could have bounded all arguments, and even more than the function
expects - the extra arguments are just ignored.
Why you do not see Function.bind used in AngularJs applications
When looking through AngularJs examples, I did not find many uses of Function.bind.
Most often people describe data binding, but not function binding. Why is there a difference
with other MVC frameworks that even
provide their own wrapper for binding an object
to callback function?
I think the answer is in clean separation between the controller and the view. All data
in AngularJS is supposed to be a property of $scope object. The framework manages
to route any ng-click to the correct scope object under the hood, without the developer
thinking about this. Inside a called function, this points to the $scope object
1 | <body ng-controller="MainCtrl"> |
when clicked the following controller function
1 | app.controller('MainCtrl', function($scope) { |
Secondary reason for not seeing function.bind used often inside AngularJs controller code:
functions that are defined inside the controller function just use $scope object to access the
data instead of properties attached to this. Even functions defined inside the link function
can directly work with the scope variable.
1 | // controller function |
Conclusion
The usefulness of function.bind to remove temporary variables cannot be
overstated. At the same time, AngularJs with its dependency injection of $scope object
mitigates the most obvious use case for preserving the right context.