Table of Contents
- Functions And Objects
- The Anatomy Of A JavaScript Function
- Statements, Expressions, And Anonymous Functions
- First-class Functions
- 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
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") }
}
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.
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") }
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:
- Name property
- 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
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!?
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
We can trap this returned value in a variable. Hence
const sumOfTwo = 2 + 2
console.log(sumOfTwo) // returns 4
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
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!!!
But we can do this instead:
const sumOfTwo = () => console.log(2 + 2);
console.log(sumOfTwo); // returns 4
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
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!"
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.
- 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.
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.
- If the data type is not a function we log that item to the console.
console.log(item)
Also Read:
DEMYSTIFYING HOISTING IN JAVASCRIPT
Lawrence Eagles ・ Apr 4 '20
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)
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):
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 aname
property. In you snippet, theresult
variable holds a function namedsumOfTwo
. You can check it out:If you had written that example without the function name, like this:
... 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.
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!
if statement
instead.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.
Is this a typo?
This produces an error:
Uncaught SyntaxError: Unexpected token '{'
Did you mean:
I'm sorry to be nitpicking but…
Hello Honza, thanks for your observation.
This is actually a typo which I have corrected. Thanks again.
However in regards to the expression:
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.
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 aFunction
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.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.
Thank you for sharing your insight with the community. I really appreciate your effort.
console.log(sumOfTwo); // returns 4
I think, you got typo. It will returns code of sumOfTwo function, not the sum :)
I have fixed this type. Thanks for your observation.