In this blog post, we will walk through the process of refactoring a function that copies an array and manipulates its elements. We'll start with a basic implementation and gradually improve it using higher-order functions in JavaScript.
The Initial Implementation
Let's start with a simple function that takes an array, copies it, and divides each element by 2.
function copyArrayAndDivideBy2(array) {
let output = [];
for (let i = 0; i < array.length; i++) {
output.push(array[i] / 2);
}
return output;
}
const myArray = [1, 2, 3];
const result = copyArrayAndDivideBy2(myArray);
console.log(result); // [0.5, 1, 1.5]
This function works, but what if we want to copy an array and apply different transformations? For example:
-
Multiply each element by 2
-
Add 3 to each element
We would have to rewrite the function multiple times for each operation, violating the DRY principle.
Refactoring for Reusability
Instead of rewriting the function for each variation, we can pass a function as an argument to define the transformation dynamically.
function copyArrayAndManipulate(array, instructions) {
let output = [];
for (let i = 0; i < array.length; i++) {
output.push(instructions(array[i]));
}
return output;
}
Here, instructions is a callback function that determines how each element is manipulated. Now, we can define different transformations separately:
function multiplyBy2(num) {
return num * 2;
}
function add3(num) {
return num + 3;
}
const result1 = copyArrayAndManipulate([1, 2, 3], multiplyBy2);
console.log(result1); // [2, 4, 6]
const result2 = copyArrayAndManipulate([1, 2, 3], add3);
console.log(result2); // [4, 5, 6]
Now, the copyArrayAndManipulate function is flexible—we only write it once and can use it with different transformations by passing different functions.
Using Arrow Functions for Simplicity
We can make our code even more concise by using arrow functions instead of defining named functions separately.
const result3 = copyArrayAndManipulate([1, 2, 3], num => num * 2);
console.log(result3); // [2, 4, 6]
const result4 = copyArrayAndManipulate([1, 2, 3], num => num + 3);
console.log(result4); // [4, 5, 6]
This approach removes unnecessary function definitions while maintaining readability.
Conclusion
By refactoring our code using higher-order functions, we've made it more reusable and maintainable. Now, instead of writing a new function for each variation, we simply pass different transformations as arguments.
Key Takeaways:
-
Avoid code duplication by following the DRY principle.
-
Use functions as parameters to make code flexible and reusable.
-
Leverage arrow functions for concise and readable code.
-
Higher-order functions enable powerful abstraction and modularity.
This is a fundamental concept in functional programming and is widely used in JavaScript, especially with built-in methods like map(), filter(), and reduce().
Happy coding!
