Anonymous functions and closures
Anonymous functions & lambda expression
An anonymous funciton (also function literal or lambda abstraction) is a function definition that is not bound to an identifier. In other world, an anonymous function is only a function without function name.
Anonymous functions are sometimes called lambda expressions.
- Python
- Go
- ES6
Closures
Wiki: In programming languages, closures (also lexical closures or function closures) are a technique for implementing lexically scoped name binding in languages with first-class functions. Operationally, a closure is a record storing a function together with an environment: a mapping associating each free variable of the function (variables that are used locally, but defined in an enclosing scope) with the value or storage location to which the name was bound when the closure was created. A closure-unlike a plain function-allows the function to access those captured variables through the closure’s reference to them, even when the function is invoked outside their scope.
MDN: Closures are functions that refer to independent (free) variables. In other words, the function defined in the closure ‘remembers’ the environment in which it was created.
Keypoints
- a function together with an environment
- unlike a plain function
- variables that are used locally, but defined in an enclosing scope which name was bound when the closure was created
Lexical scoping
init()
creates a local variable name
and then a function called displayName()
. displayName()
is an inner function that is defined inside init()
and is only available within the body of that function. displayName()
has no local variables of its own, however it has access to the variables of outer functions and so can use the variable name
declared in the parent function.
Closure
This code still works may seem unintuitive. Normally, the local variables within a function only exits for the duration of that function’s execution. Once makeFunc()
has finished executing, it is reasonable to expect that the name
variable will no longer be accessible. Since the code still works as expected, this is obviously not the case.
The solution to this puzzle is that myFunc
has become a closure. A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created. In this case, myFunc
is a closure that incorporates both the displayName
function and the “Mozilla” string that existed when the closure was created.
A closure lets you associate some data (the environment) with a function that operates on that data. This has obvious parallels to the object oriented programming, where objects allow us to associate some data (the object’s properties) with on or more methods.
Consequently, you can use a closure anywhere that you might normally use an object with only a single method.
Enulating private methods with closures
Creating closures in loops: A common mistake
- JavaScript
- golang
The bug is that in a Go for loop, the loop variable is reused for each iteration, so the req
variable is shared across all goroutines.
Here’s one way to do that, passing the value of req
as an argument to the closure in the goroutine:
Another solution is just to create a new variable with the same name, as the belows:
Performance considerations
It is unwise to unnecessarily create functions within other function if closures are not needed for a particular task, as it will negatively affect script performance both in terms of processing speed and memory consumption.
Implementation and theory
Closures are typically implemented with a special data structure that contains a pointer to the function code, plus a representation of the function’s lexical environment (i.e., the set of available variables) at the time when the closure was created. The referencing environment binds the non-local names to the corresponding variables in the lexical environment at the time the closure is created, additionally extending their lifetime to at least as long as the lifetime of the closure itself. When the closure is entered at a later time, possibly with a different lexical environment, the function is executed with its non-local variables referring to the ones captured by the closure, not the current environment.