Mastering JavaScript Functions: Complete Deep Dive
A Complete Guide to First Class Functions, Anonymous Functions, Data Handling, and Pass-by-Value vs Pass-by-Reference
JavaScript functions are first-class citizens
you can store functions in variables, pass them to other functions as arguments, and return them from other functions as values.
function sum(a, b) {
return a + b;
}
let add = sum;
console.log(add);
// calling the function in two ways
add = sum(2, 4); // normal way
let resultOne = add(2, 4); // assigned way
console.log(add);
console.log(resultOne);
// passing function to another function
function avarage(a, b, fn) {
return fn(a, b) / 2;
}
let resultTwo = avarage(10, 20, add);
let resultThree = avarage(10, 20, sum);
console.log(resultTwo);
console.log(resultThree);
putting altogether
function multiply(a, b) {
return a * b;
}
let multi = multiply;
function multiplyAverage(a, b, multi) {
return multi(a, b) / 2;
}
let multiResult = multiplyAverage(5, 4, multi);
console.log(multiResult);
Returning functions from functions
Since functions are values, you can return a function from another function.
function compareBy(propertName) {
return function (a, b) {
let x = a[propertName];
let y = b[propertName];
if (x > y) {
return 1;
} else if (x < y) {
return -1;
} else {
return 0;
}
};
}
let products = [
{
productName: "Samsung",
price: 1500,
year: 2023,
},
{
productName: "Lava",
price: 500,
year: 2024,
},
{
productName: "Apple",
price: 1800,
year: 2022,
},
{
productName: "Google",
price: 1000,
year: 2024,
},
];
console.log("Product sorted by Name: ");
products.sort(compareBy("productName"));
console.table(products);
Anonymous Function
A function that is declared without a name. They are often used when the function is used only once and does not need to be reused.
(function (params) {
// Function Body
})();
if you don’t place the anonymous function inside the parentheses
()
, you’ll get a syntax error. The parentheses()
make the anonymous function an expression that returns a function object.Anonymous functions can be assigned to a variable, passed as an argument to another function, or used as a value in an expression. Example is
function expression
Types of Anonymous Functions
IIFE - Immediately invoked function execution
Arrow functions
IIFE - Immediately invoked function execution
If you want to execute a function immediately after it is declared, you can wrap the function in parentheses and add a set of parentheses. This is called immediate invocation or immediately executed function expression (IIFE).
They are often used to create a private scope and avoid polluting the global namespace.
(function () {
console.log("I am IIFE");
})();
passing arguments into an anonymous function
let person = {
firstName: "Jhon",
lastName: "Smith",
};
(function () {
console.log(
`Employee first name is ${person.firstName} and the last name is ${person.lastName}`
);
})();
Arrow functions
The Arrow Function is introduced in ES6 (ECMAScript 2015) and provide a more compact syntax compared to traditional function expressions. The arrow function is defined but not immediately invoked. You can assign it to a variable or return it from another function.
Arrow functions do not have their own this
binding. Instead, they inherit the this
value from the enclosing scope. This makes arrow functions particularly useful when working with callback functions or methods that require a specific this
value.
// single line arrow function
const add = (a, b) => a + b;
console.log(add(2, 3)); // Output: 5
// Multi-line arrow function
const multiply = (a, b) => {
const result = a * b;
return result;
};
console.log(multiply(2, 3)); // Output: 6
Using anonymous functions as arguments
In reality, You often pass anonymous functions as arguments to other functions.
setTimeout(function () {
console.log("Executed after 5 seconds");
}, 5000);
Advantages
Concise Code: Anonymous functions are great for writing concise code, especially when you need a small, one-time-use function.
Reduced Memory Usage: Anonymous functions use less memory than named functions because they don't require storing a reference to the function in memory.
Scope Encapsulation: They can be used to encapsulate functionality within a local scope without cluttering the global scope.
Disadvantages
Limited Debugging: Since anonymous functions are not assigned to a variable, debugging can be more challenging, especially when trying to understand complex code.
Readability: Anonymous functions can make code less readable, especially when they are used extensively or nested within other functions. -No Reusability: Anonymous functions cannot be reused in other parts of your code without redefining them.
When to Use
One-time-use Functions: Use anonymous functions when you need a small, one-time-use function that doesn't require reusability or debugging ease.
Concise Code: Use anonymous functions when you want to write concise code and don't mind the potential drawbacks.
Small Callbacks: Use anonymous functions as callbacks in event listeners or timeouts where you only need a small, one-time-use function.
Immediate execution: Anonymous functions can be used to execute code immediately, without the need for a named function.
When Not to Use
Reusable Functions: Avoid using anonymous functions for reusable functions that require debugging ease or reusability.
Complex Logic: Don't use anonymous functions for complex logic or algorithms that require readability and maintainability.
Recursive functions: Anonymous functions can lead to confusion when used for recursive functions, as they do not have a name that can be easily referenced within the function.
Large-Scale Applications: In large-scale applications, it's generally better to avoid anonymous functions in favour of named functions for easier maintenance and debugging.
JavaScript pass-by-value or pass-by-reference
On a high level, we can say that,
pass-by-value
means passing an actual value.pass-by-reference
means passing a reference instead of an actual value.
Before understanding what is pass-by-value
and pass-by-reference
, let's understand the different data types and how different data types are stored in memory.
There are 2 types of data types are there in JavaScript
Primitive data types
String
Number
Bigint
Boolean
Undefined
Null
Symbol
Object
Non-primitive data types
objects
arrays
date
maps
sets
Primitive data types
In primitive data types variable stores actual value. and each primitive data type is stored in a separate memory space.
This means when you assign a variable to another variable copy of the value will be assigned not the memory address.
let number = 10;
let message = "Hi";
let numberTwo = 10;
let numberThree = number;
Identifier | Value |
number | 10 |
message | Hi |
numberTwo | 10 |
numberThree | 10 |
What will happen when you update the primitive value?
let number = 10;
let message = "Hi";
let numberTwo = 10;
let numberThree = number;
numberThree = numberThree + 1;
Identifier | Value |
number | 10 |
message | Hi |
numberTwo | 10 |
numberThree | 11 |
Non-primitive data types
When a non-primitive data type is created it is stored in a heap memory. Heap memory is a region of the memory which is used for dynamic memory allocation.
When a non-primitive data type is created, a reference to that data type is stored on the stack, while the actual data is stored in the heap.
let evenNumbers = [2, 4, 6];
let evenNumbersTwo = evenNumbers;
Identifier | Value | Address | Value |
evenNumbers | <0x01> | <0x01> | [2, 4, 6] |
evenNumbersTwo | <0x01> |
In the above example, you can see that the value stores the reference to the memory address, not the actual value.
When we assign a variable to another variable copy of the address will be assigned to it not the value and the new variable will refer to the same memory address.
let evenNumbers = [2, 4, 6];
let evenNumbersTwo = evenNumbers;
evenNumbersTwo.push(8)
Identifier | Value | Address | Value |
evenNumbers | <0x01> | <0x01> | [2, 4, 6, 8] |
evenNumbersTwo | <0x02> | <0x02> | [2, 4, 6, 8] |
In non-primitive data types if you change the value for any one variable the value will be changed to all the variables having the same reference.
evenNumbersTwo = [10, 12, 14]
Identifier | Value | Address | Value |
evenNumbers | <0x01> | <0x01> | [2, 4, 6, 8] |
evenNumbersTwo | <0x02> | <0x02> | [10, 12, 14] |
When you rewriting the variable with the new value it will use the different memory address to store the value.
We understood how Primitive and Non-Primitive data types are stored in the memory. We can easily understand the difference between pass-by-value
and pass-by-reference
now.
If you want a quick summary then
pass-by-value
is Primitive data types and pass-by-reference
is a Non-Primitive data type. Let us take an example and understand both.
pass-by-value
function square(x){
x = x * x;
return x;
}
let y = 10;
let result = square(y);
console.log(y); // 10
console.log(result); // 100
First, declare
square(x)
function which acceptsx
as a parameter and returnsx
after calculating the value of thex
.Next, declare
y
variable and assign value10
. Then pass they
variable tosquare(y)
function. Once we pass they
variable tosquare(y)
function, the value of they
variable is copied intox
.square(x)
function will calculate the value ofx
and returns it. Now the value ofx
is100
and value ofy
is10
because primitive values always copy the value, not the reference.Then the
result
variable is updated with thex
value which is100
pass-by-reference
let person = {
name: 'John',
age: 25,
};
console.log(person);
function increaseAge(obj) {
obj.age += 1;
}
increaseAge(person);
console.log(person);
First, we define an object called
person
with two propertiesname
andage
.Next, we define
increaseAge(obj)
function which takesobj
as a parameter and increases theage
property ofobj
parameter.Then, we pass the
person
object intoincreaseAge(obj)
function. When theperson
is passed intoincreaseAge(obj)
function, theobj
will also point to the same reference asperson
object.After that
age
property of theperson
object is increased inside theincreaseAge(obj)
function viaobj
variable.Finally, accessing the object via the
person
object.
when passing an object to a function, you are passing the reference of that object, not the actual object. Therefore, the function can modify the properties of the object via its reference. However, you cannot change the reference passed into the function.
let person = {
name: 'John',
age: 25,
};
function increaseAge(obj) {
obj.age += 1;
// reference another object
obj = { name: 'Jane', age: 22 };
}
increaseAge(person);
console.log(person);
Conclusion
In this article,
I have explained how functions in JavaScript are first-class citizens and how this provides flexibility. They can be stored in variables, passed as arguments, and returned from other functions.
Then, I explained what an anonymous function is, its types, advantages, disadvantages, and the appropriate situations for its use.
Then, I explained the differences between primitive and non-primitive data types, how they are stored in memory, how they are accessed, and what happens when you make changes to them.
Finally, I have discussed how pass-by-value
and pass-by-reference
work in JavaScript, and what occurs when modifications are made to them.
Thank you for taking the time to read this article 😊. I hope the article provided you with valuable insights. I would highly appreciate it if you took a moment to like 👍, share your thoughts or feedback comment ✍️, and share 🔁 it.
You can also follow me for more content on CSS, Javascript, React, Git and other web Development topics.
Happy Learning...! ✌️✌️✌️
For Paid collaboration, please mail me at: subramanyeshwarak@gmail.com
If you liked my content, Connect with me on