Lambda expressions
Invented in the 1930s, when most programmers use the term lambda expression they mean: a function that can be passed to other functions.JavaScript is an interpreted language and this means that it treats code and data in much the same way. A variable can store data or code, with the only real difference being that code can be executed using, for example, the invocation operator (). The usual way to define a JavaScript function covers up this unity. For example, the definition:
function test(a) { alert(a); }…looks like a standard function creation. However it’s just shorthand for:
test=function(a){ alert(a); }You can think of test as being a variable that just happens to hold a reference to a function. You can assign one function to another using standard syntax:
var test2=test; test2("hello2");…and this works perfectly. Notice that while test and test2 are both references to the code that make up the function, they don’t behave quite like a simple reference. In particular if you redefine test a new block of code is created on the heap and test is set to point to it. The second variable, test2, still points to the original block of code and hence the old version of the function. In this example:
test=function(){alert("Hello1");}; test2=test; test=function(){alert("Hello2");};…test is a function that prints Hello2 but test2 is still the original function that prints Hello1, as you can confirm by using:
test(); test2();In this sense JavaScript functions are immutable – you can’t modify them, only create completely new functions.
You can use this function reference mechanism to create something that looks like C#’s multi-target delegate function. To call multiple functions with a single call you could use something like:
func1=function(){ list of instructions 1}; func2=function(){ list of instructions 2}; func3=function(){ list of instructions 3}; func= function(){{func1(); func2();func3()};…and to call all three sequentially, use:
func();You can pass parameters, and pass them on to the sequence of called functions – useful for implementing a “callback” that invokes multiple functions.
Given you can pass a standard variable into functions, it’s reasonable that you can pass a variable that just happens to contain a function into another function. Recall that all parameters in JavaScript are passed by reference, so just a pointer to the function is passed and this is efficient.
For example, the Array object has a method that will sort the array into order:
var list=new Array( "A","AB","ABC","ABCD"); list.sort(); for(var i=0;i<list.length ;i++) { alert(list[i]); }Perhaps less well known is that the sort method can take an optional function to compare the values of the array:
function(a,b)It has to return a negative if a<b, 0 if a==b and positive if a>b. For example:
compare=function(a,b) { return a.length-b.length; }…used in:
list.sort(compare);…sorts the list of strings into order based on their length alone.
As JavaScript also supports anonymous functions you can even write this as:
list.sort(function(a,b) {return a.length-b.length;});Of course there is nothing stopping you from creating your own functions that accept other functions. For example:
Say=function(t) { t(); }…will call any function that you pass to it. If you define:
Greet=function() { alert(“Hello”); } Say(Greet);…will call the Greet function and display an alert. Notice that you have to pass the variable that stores the function without accidentally invoking it first. Don’t write:
Say(Greet());…by mistake as this would call the Greet function and then pass its result, undefined in this case, to the Say function. Distinguish between passing a function and passing the result of a function to another function.
You need to get into the habit of thinking of the () brackets as being the function invocation operator. Whenever you use () following an expression, it calls the function that is the result of the expression. For example you can write:
(Say)(Greet);…or even:
Say=function(t) { t(); } (Greet);The round brackets at the end of the function definition call the function as soon as it has been defined. This can be useful when you want to pass the result of a lambda expression. For example:
alert(function sum(a,b) {return a+b;}(1,2));Here we have a lambda expression, the sum function being defined and evaluated in a single step. The result, 3 in this case, is passed to the alert function.
All of this becomes more useful when combined with other features such as closure – more of which another time.
Ian Elliot is a development programmer with I/O Workshops, a consultancy which solves real world problems for clients with varying requirements.
Comments