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.