Anonymous functions and closures are a useful concepts included in most modern programming languages. Like so many elements of modern programming, the closure has its origins in the early Lisps.
Anonymous functions are used heavily in JavaScript for many things, most notably the many callbacks used by the language’s many frameworks. In Ruby we see them most often in their block format.
First let’s look at anonymous functions. An anonymous function allows a developer to create a function that has no name. In other words anonymous functions can be used to store a bit of functionality in a variable and pass that piece of functionality around. First let’s look at an example using an anonymous function in Ruby and JavaScript:
[1, 2, 3].map do |number_to_double|
number_to_double * 2
end
_.map([1, 2, 3], function(numberToDouble) {
return numberToDouble * 2
})
Above we use the Ruby Array
‘s map
method and the JavaScript library
Lo-Dash’s map method. In
both cases we provide a callback. The Ruby example uses a block and the
JavaScript example uses a function. These callbacks are anonymous functions. We
specify a bit of functionality, in this case multiplying the number provided by
two, and then pass that functionality to the map
method. In our example the
resulting array would be [2, 4, 6]
. Because we’re allowed to define the
functionality we want to use to modify the elements of our array it makes it
much easier to create reusable code. As opposed to creating many different map
methods, each that modified the contents of the array in a different way, we
only need one that allows us to provide it with the functionality our specific
use case requires.
Closures have to do with the connection between functionality and the variables that are available to said functionality when it’s executed. When a closure is created it can reference any of the variables available in its lexical scope and as a result is said to close over its environment. This raises the question, what is a lexical scope? Lexical scoping simply means that variables refer to their local environment.
Let’s look at an example to help clarify:
Ruby lexical scoping
def lexical_scope_example(multiplier)
[1, 2, 3].map do |number|
new_number_to_double = number * multiplier
new_number_to_double * 2
end
end
> lexical_scope_example(5)
=> [10, 20, 30]
In our Ruby example we have two lexical scopes:
- The
lexical_scope_example
function has the parametermultiplier
- The block we pass to the
map
method can access themultiplier
,number
andnew_number_to_double
variables
JavaScript lexical scoping
function lexicalScopeExample(multiplier) {
return _.map([1, 2, 3], function(number) {
var newNumberToDouble = number * multiplier
return newNumberToDouble * 2
});
}
> lexicalScopeExample(5)
=> [10, 20, 30]
In our JavaScript example we have two lexical scopes:
- The
lexicalScopeExample
function has the parametermultiplier
- The block we pass to the
map
method can access themultiplier
,number
andnewNumberToDouble
variables
It’s interesting to note that the block’s lexical scope includes the variables
which belong to the lexical scope it is created in. The inverse is not true.
Variables defined in the block’s lexical scope are not then available to the
function’s lexical scope. Let’s take a look at what happens if we try to access
the new_number_to_double
variable outside of the block’s lexical scope. In
this case our anonymous function has closed over its environment.
Ruby variable outside of block’s scope
def lexical_scope_example(multiplier)
[1, 2, 3].map do |number|
new_number_to_double = number * multiplier
new_number_to_double * 2
end
puts new_number_to_double
end
> lexical_scope_example(5)
=> NameError: undefined local variable or method `new_number_to_double' for main:Object
JavaScript variable outside of block’s scope
function lexicalScopeExample(multiplier) {
return _.map([1, 2, 3], function(number) {
var newNumberToDouble = number * multiplier
return newNumberToDouble * 2
});
console.log(newNumberToDouble)
}
> lexicalScopeExample(5)
=> ReferenceError: newNumberToDouble is not defined
Now that we’ve taken a look at lexical scope let’s revisit how they pertain to closures. Closures allows us to define units of functionality while maintaining references to all the variables that exist in the lexical scope they are defined. These units of functionality can then be executed in a different lexical scope. Let’s take a look at an example.
Ruby in different lexical scope
def scope_two
yield
end
def scope_one
closure_addend = 3
scope_two do
closure_addend += 5
end
puts "The variable in our main lexical scope after the method is executed
equals #{closure_addend}"
end
> scope_one
=> "The variable in our main lexical scope after the method is executed equals 8"
In our Ruby example we have three lexical scopes:
- The
scope_one
function includes theclosure_addend
variable - The block we define when we call the
scope_two
function includes theclosure_addend
variables
Let’s walk through the Ruby version step by step:
- In irb we call our
scope_one
function - Within this function we create the
closure_addend
variable and assign it the value of 3 - Within the lexical scope of our
scope_one
function we define a block and pass it to thescope_two
function - Inside the new lexical scope of the
scope_two
function we execute our closure - Inside of our closure we add 5 to the
closure_addend
variable we defined within the lexical scope of thescope_one
function - We then return to our
scope_one
lexical scope andputs
ourclosure_addend
variable, which has now been incremented by 5
JavaScript in different lexical scope
function scopeTwo(callback) {
callback();
}
function scopeOne() {
var closureAddend = 3;
scopeTwo(function() {
closureAddend = closureAddend + 5;
});
console.log("The variable in our main lexical scope after the method is
executed " + closureAddend);
}
> scopeOne()
=> "The variable in our main lexical scope after the method is executed equals 8"
In our JavaScript example we have three lexical scopes:
- The
scopeOne
function includes theclosureAddend
variable - The function (closure) we pass when we call the
scopeTwo
function includes theclosureAddend
variables
Let’s walk through the JavaScript version step by step:
- In the browser console we call our
scopeOne
function - Within this function we create the
closureAddend
variable and assign it the value of 3 - Within the lexical scope of our
scopeOne
function we define a function and pass it to thescopeTwo
function - Inside the new lexical scope of the
scopeTwo
function we execute our closure that we calledcallback
- Inside of our closure we add 5 to the
closureAddend
variable we defined within the lexical scope of thescopeOne
function - We then return to our
scopeOne
lexical scope and log ourclosureAddend
variable, which has now been incremented by 5
The interesting part of this is that our closure gets executed in a completely different lexical scope than it was created in, but still has access to the variables in the original scope. It’s also important to notice that the modifications that occur in the new lexical scope affect original value, because it is the same value.
Let’s take a look at what would happen if we attempted to access the
closure_addend
variable in the scope_two
function’s lexical scope.
Ruby variable in other method’s scope
def scope_two
yield
puts "We just modified this variable in the block above #{closure_addend}"
end
def scope_one
closure_addend = 3
scope_two do
closure_addend += 5
end
puts "The variable in our main lexical scope after the method is executed #{closure_addend}"
end
> scope_one
=> `scope_two': undefined local variable or method `closure_addend'
for main:Object (NameError)
JavaScript variable in other method’s scope
function scopeTwo(callback) {
callback();
console.log("We just modified this variable in the block above " + closureAddend);
}
function scopeOne() {
var closureAddend = 3;
scopeTwo(function() {
closureAddend = closureAddend + 5;
});
console.log("The variable in our main lexical scope after the method
is executed " + closureAddend);
}
> scopeOne()
=> ReferenceError: closureAddend is not defined
The ability to maintain references to the lexical scope at the time of definition is especially useful in callbacks. This is used extensively in JavaScript. It’s common to provide an asynchronous action with a callback to be executed upon completion. The lexical scope that this callback is executed in is often the framework’s we’re using.
What’s next
If you found this useful, you might also enjoy: