Lambdas and anonymous functions in JavaScript

There's a lot of confusion in the JavaScript community around the term “lambda”.

I'll eschew pointing to any particular examples, as they can get pretty heated. It all revolves around the terms "lambda expression" (or "lambda", for short), a term which originated in the mathematical side of computer science, and "anonymous function", which is a programming term. So what's going on here?

Functions in JavaScript are values that can be passed around like any other values, e.g. string values, number values, or other object values. This is sometimes expressed in the phrase “functions as first class citizens”.

It's best to think of these values like actual values: a function value is just some object living in memory. Let me be clear: when I say function value here, I don't mean the value taken by a function on some input, I mean the function object itself: the value in memory that the function is, itself, per se, intrinsically (mind blown).


It is worth here keeping a distinction in mind between reference types and value types. Functions are a reference type, whereas types like strings or numbers are value types. For value types, we get the following behavior as one might expect:

> 2 === 2
true
> 2+2 === 4
true
> 'four' === 'four'
true
> 'f'+'our' === 'four'
true

But for functions, we create separate objects each time we evaluate a function literal:

> ((x) => x + x) === ((x) => x + x)
false

Arrays work similarly:

> [1,2,3] === [1,2,3]
false

If you come from a C background, you can think of what JavaScript is doing when it evaluates the array literal [1,2,3] as creating a new array in memory, dumping the contents 1,2,3 into consecutive addresses in memory, and returning a pointer to the first address (the one storing the 1).


In JavaScript, a function is defined either within a function declaration, or a function expression. A function declaration announces to the JavaScript engine that it should note information about the existence of a function, and attaches it to an identifier within the enclosing environment. A declared function is “named” within its enclosing environment, so it can be called later.

How is this done? Pretty much how you might expect: when an environment is created , a map of key-value pairs is created which translates identifiers into the objects in scope. Whenever we have a call to some name in that environment (or, with lower priority, in a child environment), we can look at the identifier table to find out what object the name refers to.

The very basic but very important thing to realize here is this: to tell whether a function is “anonymous” or “named” depends on which environment we're talking about. The name of a function is a property of the environment, not of the function. Within a given environment, the named functions are those functions with names in the key-value store of identifiers, the anonymous functions are all the other functions.

Unfortunately, JavaScript makes it more confusing than that: in JavaScript, the function object itself may have a property field, called name. You can understand why such a property would be useful: recursion and debugging logs come to mind. However some sort of “name”-ish thing, which is a property of a function rather than a property of an enclosing environment, is very much a different concept from an identifier as we talk about them in general programming.

For example, let's use a JavaScript function expression to define a function with a name property of foo, and then try to call it as if that name were a valid identifier:

> let fooVar = function foo (x) { return x+x };
undefined
> fooVar.name;
'foo'
> foo(2);
Uncaught ReferenceError: foo is not defined

We can see that in fact, whatever the “name” field of this function which holds foo is, it certainly doesn't provide an identifier within the enclosing environment. It's a named anonymous function? Oh sure it has a name, but it keeps that name anonymous to everyone else. If you prefer to sweep the unpleasant contradiction under the rug, Mozilla calls this a named function expression.

In fact, the name field does serve as an identifier, but not in the environment the function is being used in: it serves as an identifier within the function's own function environment. Again, the essential point: whether a function is anonymous or not is a property of the environment, not the function: foo above is anonymous in the outside environment, but named in its own environment. For example:

> 8 + function foo (n) {return (n < 2) ? 1 : foo(n-2) + foo(n-1)}(6);
21

Of course, in our fooVar example we did provide, in a roundabout way, an identifier for this function in the variable named fooVar. In fact, if we don't provide an explicit name for the name field, ECMAScript's spec requires that an assignment of a variable identifier to also set the internal name field of the function object constructed, even works for arrow functions:

> let foo = (x) => {x + x};
undefined
> foo.name;
'foo'
> foo(2);
4

If you don't like the variable assignment example because it still had the identifier fooVar, rest assured we can have genuinely “named anonymous functions” in JavaScript:

> 0 + function foo (x) {return x + x } (2);
4
> "this function is named " + function foo (x) {return x + x} . name;
"this function is named foo"
> foo(2);
Uncaught ReferenceError: foo is not defined

Alright, so the term anonymous function is a bit tricky when applied to JavaScript. What about lambda? Well, the best equivalent (within the JavaScript world) to the meaning of the phrase lambda expression (outside the JavaScript world) is function expression.

JavaScript has always had function expressions, even before it introduced the arrow function expressions notation that approximates the syntax of lambda expressions from the lambda calculus and other languages with similar syntax.

Nowadays, if someone talks about a lambda in JavaScript, they're often referring to a function expression that uses the arrow function syntax, or they could simply be referring to any function expression. It can be important to distinguish between function expressions and arrow function expressions, since they behave a little differently with how their this and arguments properties are constructed.


So what's the lesson to be learned here? Well, it's best to avoid the term anonymous function and lambda in JavaScript. JavaScript has function declarations,
function expressions, and arrow function expressions, and those are the best terms to use.

If you have to translate general computer science ideas from outside the JavaScript world into the JavaScript world: lambda expression, anonymous function, and function expression, and function literal from the outside world all translate to function expression and arrow function expression in the JavaScript world.

Function expressions can be named or anonymous, but it's important to understand how that distinction has to do with an internal property of functions in JavaScript, whereas the general computer-science concept of anonymous function has to do with lexical scoping and bound identifiers within an environment.