DEV Community

Cover image for UNDERSTANDING FIRST-CLASS FUNCTIONS AND ANONYMOUS FUNCTIONS IN JAVASCRIPT
Lawrence Eagles
Lawrence Eagles

Posted on • Edited on

UNDERSTANDING FIRST-CLASS FUNCTIONS AND ANONYMOUS FUNCTIONS IN JAVASCRIPT

Table of Contents

  1. Functions And Objects
  2. The Anatomy Of A JavaScript Function
  3. Statements, Expressions, And Anonymous Functions
  4. First-class Functions
  5. Closing Thoughts

1. FUNCTIONS AND OBJECTS

You might be a little surprised at this subtitle. This is because in JavaScript functions are objects.
They are actually a special kind of objects with some unique properties in them. It is often a subject of debate in JavaScript, on what to teach first between functions and objects. I am of the school of thought that both should be taught at the same time. This is because in JavaScript, functions and objects are very intertwined and in many ways they are similar.
With that said, I would like to do a quick refresher on objects in JavaScript before proceeding to functions.

Objects in JavaScript

They are just a collection of key-value pairs.

{ key: value, key: value, key: value } // a dummy example
Enter fullscreen mode Exit fullscreen mode

An object property's value can be any primitive data type in JavaScript e.g: Strings, Numbers, Boolean. It can even be another object. In all of these cases, they are referred to as the object property. On some occasions, the value can be a function. when the value is a function that function is called a method.
we can access an object property's value by passing the key to special operators in JavaScript viz the member access operator and the computed member access operator. Let's take a quick look at this.

const dog = {}; // creates an empty dog object
dog.legs = 4; // adds a leg property using member access operator
dog["bark"] = "woaf woaf"; // adds a bark property using computed member access operator
dog.details = {owner: "Tim", name: "Jack"} // adds details property which is another object using the member access operator
dog["run"] = function(){ console.log("running dog") } // adds a method using the computed member access operator 
console.log(dog) // returns 
{
  legs: 4,
  bark: "woaf woaf",
  details: { owner: "Tim", name: "Jack" },
  run: function() { console.log("running dog") }
}
Enter fullscreen mode Exit fullscreen mode

In the example above I have used both the member access operator (which is just the dot) and the computed member access operator (the square braces []) to add properties and a method to the object. Both operators look for the property to be added in the object and if they cannot find it they would create it there.

One key point to note and carry along is that we could have easily created the dog object with all the properties on the fly. Like this:

const dog = {
  legs: 4,
  bark: "woaf woaf",
  details: { owner: "Tim", name: "Jack" },
  run: function() { console.log("running dog") }
}
console.log(dog) // returns
{
  legs: 4,
  bark: "woaf woaf",
  details: { owner: "Tim", name: "Jack" },
  run: function() { console.log("running dog") }
}
// we still get the same result but this is faster.
Enter fullscreen mode Exit fullscreen mode

Another important thing to note and carry along is that an object holds the references (addresses) of all its properties and methods in your computer's memory. It knows where they all sit in memory
As a result of this, we can access them using these same operators. Hence:

console.log(dog["legs"]) // returns 4
console.lg(dog["details"] // returns { owner: "Tim", name: "Jack" }
console.log(dog.bark) // returns "woaf woaf"
console.log(dog.run) // return function(){console.log("running dog") }
Enter fullscreen mode Exit fullscreen mode

2. THE ANATOMY OF A JAVASCRIPT FUNCTION

Javascript functions are special objects. They have the same properties as other objects but have some extra properties that make them first-class objects or first-class citizens as some call it. Two of these are:

  1. Name property
  2. Code property

A function object has a name and a code property.

function ageTeller(age){
    console.log(`my age is ${age}`);
}
console.log(ageTeller.name) //returns ageTeller
console.log(ageTeller.length) // returns length of the function
Enter fullscreen mode Exit fullscreen mode

The function's code property is an object that holds all that function's code that you wrote. It is not accessible publicly and it is stored in an internal property [[Code]]. Read more from the ecma-international.org
In other words, the code you wrote is not the function itself but sits in the code property of the function. A function is just a special object in JavaScript

TWO IMPORTANT TIPS:
  • This code property of a function is invokable. And this is how a function gets called or invoked in JavaScript.
  • A function in JavaScript must not necessarily have a name. Hence we can create a function without giving it a name. In this case, that function is said to be anonymous.
const anonymousAgeTeller = function(age){
    console.log(`my age is ${age}`);
}
// A function without a name!?

const es6AnonymousAgeTeller = age => console.log(`my age is ${age}`);
// An es6 arrow function without a name!?
Enter fullscreen mode Exit fullscreen mode

3. STATEMENTS, EXPRESSIONS, AND ANONYMOUS FUNCTIONS

The functions above do not have a name. Both are the same but the latter es6AnonymousAgeTeller, uses modern JavaScript syntax. And that is what will be using as we go on.

It is interesting to see that we are assigning a function expression to a variable es6AnonymousAgeTeller. This is perfectly valid JavaScript and it opens the door for some very powerful coding patterns.

An expression is a unit of code that returns a value.

2 + 2 // returns 4 
3 > 2 // returns true
Enter fullscreen mode Exit fullscreen mode

We can trap this returned value in a variable. Hence

const sumOfTwo = 2 + 2
console.log(sumOfTwo) // returns 4
Enter fullscreen mode Exit fullscreen mode

A statement, on the other hand, is a unit of code that does work. It does not return a value. Take Note.

function sumOfTwo () {
   console.log(2 + 2);
}
// a function statement does not return a value.
// A value is only returned when the function is invoked/called
sumOfTwo() // returns 4
Enter fullscreen mode Exit fullscreen mode

we cannot assign a statement to a variable because it does not return anything.

const result = if(3 > 2) {
  return "the result is true"
}
// wrong JavaScript code and should not be done!!!
Enter fullscreen mode Exit fullscreen mode

But we can do this instead:

const sumOfTwo = () => console.log(2 + 2);
console.log(sumOfTwo); // returns 4
Enter fullscreen mode Exit fullscreen mode

Above I wrote a function expression which is a function that does not have a name and because it is an expression it returns the reference of that function (its address in your computer's memory, at this time the function is not called so the reference is returned) and this is stored in the variable sumOfTwo. We can now invoke/call this function's code property using the sumOfTwo variable since this variable now holds a reference to the function in memory. Hence:

console.log(sumOfTwo()); // returns 4
Enter fullscreen mode Exit fullscreen mode

These kinds of functions that do not have names in JavaScript are called Anonymous functions.

4. FIRST-CLASS FUNCTIONS

Anonymous functions can be stored in a variable, object, or array, passed as an argument to a function and can even be returned from a function. Hence they are called first-class functions or first-class object or as some call it first-class citizens in Javascript
In a nutshell, they can be treated and used as you would use any primitive JavaScript data type

This makes JavaScript extremely powerful. Below are some examples to buttress this idea.

function logItem (item) {
    if(typeof item === "function") {
      console.log(item());
    }else {
    console.log(item);
    }
}

console.log(logItem("Lawrence Eagles")) // returns "Lawrence Eagles"
console.log(logItem({name : "Lawrence Eagles", location: "Earth"})) // returns {name : "Lawrence Eagles", location: "Earth"}
console.log(logItem(()=> {
    console.log("I am a first-class citizen in JavaScript!")
})) // returns "I am a first-class citizen in JavaScript!"
Enter fullscreen mode Exit fullscreen mode
Let's breakdown the function above.
  • The function name is logItem and it takes a parameter called item
  • we get the data type of the parameter using the typeof operator. The typeof operator returns a string indicating the type of the unevaluated operand.
typeof item
// this is an expression so it returns a value depending on the data type of item.
Enter fullscreen mode Exit fullscreen mode
  • We take that returned data type and check if it is equal to "function"
typeof item === "function" 
// take note typeof returns it's result as string. so we check if the result is equal to a "function".
// This is another expression and it would return true or false in this case.
Enter fullscreen mode Exit fullscreen mode

If true, we know that a first-class anonymous function was passed and its reference would now be stored in the logItem function's parameter. So we call that first-class function using the logItem parameter

item()
// item is going to hold any argument passed to the function. 
// If a primitive is passed it would hold that primitive but if a function is passed it would hold a reference to the function in memory. 
// So we can invoke the code property of that function using this parameter.
Enter fullscreen mode Exit fullscreen mode
  • If the data type is not a function we log that item to the console. console.log(item)

Also Read:

5. CLOSING THOUGHTS

This concept of first-class functions opens up a whole new programming paradigm in JavaScript called functional programming. This gives JavaScript superpowers and makes it a very good language for functional programming. I do hope you got a thing or two from this article and I am very much looking forward to your additions or questions in the comment section below.

Top comments (10)

Collapse
 
fhpriamo profile image
Fábio Priamo • Edited

Hi Lawrence! Just want to comment on something that bothered me a little bit:

There is absolutely nothing wrong with the snippet you wrote (except for the comment):

const result = function sumOfTwo () {
   console.log(2 + 2);
}
// wrong JavaScript code and should not be done!!!
Enter fullscreen mode Exit fullscreen mode

It's actually (very) valid JavaScript, and it is not really a statement, but a function expression (please, browse for "FunctionDeclaration" and "FunctionExpression" on the ECMAScript spec you referenced).

Additionally, note that Function objects have a name property. In you snippet, the result variable holds a function named sumOfTwo. You can check it out:

result.name  // returns 'sumOfTwo'
Enter fullscreen mode Exit fullscreen mode

If you had written that example without the function name, like this:

const result = function() {
   console.log(2 + 2);
};
Enter fullscreen mode Exit fullscreen mode

... the function name would be inferred by the name of the variable ('result') or set to an empty string or 'anonymous' in versions prior to ES6.

result.name  // returns 'result'
Enter fullscreen mode Exit fullscreen mode

Also, note that naming function expressions is considered good practice and there is even an ESLint rule that enforces this behaviour.

One last silly note before I go: the internal property of the function is [[Code]], with a capital 'C'.

Cheers!

Collapse
 
lawrence_eagles profile image
Lawrence Eagles
  • You are totally right. The function declaration can be assigned to a variable and even called from there. I have updated this article accordingly I now use an if statement instead.
const result = if(3 > 2) {
  return "the result is true"
}
// wrong JavaScript code and should not be done!!!
Enter fullscreen mode Exit fullscreen mode
  • I did mention that functions have a name property with this example:
function ageTeller(age){
    console.log(`my age is ${age}`);
}
console.log(ageTeller.name) //returns ageTeller
console.log(ageTeller.length) // returns length of the function
Enter fullscreen mode Exit fullscreen mode
  • The [[Code]] property is updated too. I confirmed it. Thanks.
Collapse
 
stereobooster profile image
stereobooster • Edited

Side note: all-caps words are harder to read. Humans (typically) don't read letter by letter, rather they read the whole word at once and use shape of the word to read it. For all-caps words shape is the same (rectangle), so we forced to fallback to reading letter by letter, which takes longer.

Collapse
 
crs1138 profile image
Honza • Edited

Is this a typo?

const anonymousAgeTeller = (age){
    console.log(`my age is ${age}`);
}

This produces an error: Uncaught SyntaxError: Unexpected token '{'

Did you mean:

const anonymousAgeTeller = function(age){
    console.log(`my age is ${age}`);
}

I'm sorry to be nitpicking but…

2 + 2
// this is an arithmetic expression, 
// the + sign in this context is an arithmetic operator
// not a function. Try console.dir(+), you get an error.

Collapse
 
lawrence_eagles profile image
Lawrence Eagles • Edited

Hello Honza, thanks for your observation.

const anonymousAgeTeller = (age){
    console.log(`my age is ${age}`);
}

This is actually a typo which I have corrected. Thanks again.

However in regards to the expression:

2 + 2

This is actually an arithmetic expression no doubt and as understand it, the addition operator is a special function that uses the infix notation and returns the value of adding its two operands.
So it is a function.
I did not fully understand you here.

Collapse
 
crs1138 profile image
Honza

Hi Lawrence,
first of all, I'd like to thank you for the article. I think it's brilliant! And thanks for getting back to me this quickly and fixing the typo.

I'll elaborate a bit on the + operator. What I meant, it's not a Function object. The compiler likely works with it as an infix function, but strictly speaking, it is not a Javascript function as such. I just believe that the example adds unnecessary confusion to the topic.

Thread Thread
 
lawrence_eagles profile image
Lawrence Eagles

Hello, Honza,
Now I understand you better. I have removed those ambiguous sections of the article.
Thanks for helping improve the quality, you are appreciated.

Thread Thread
 
crs1138 profile image
Honza

Thank you for sharing your insight with the community. I really appreciate your effort.

Collapse
 
vladyslavkhrystych profile image
Vladyslav Khrystych

console.log(sumOfTwo); // returns 4

I think, you got typo. It will returns code of sumOfTwo function, not the sum :)

Collapse
 
lawrence_eagles profile image
Lawrence Eagles

I have fixed this type. Thanks for your observation.